其他分享
首页 > 其他分享> > 破坏正方形UVA1603

破坏正方形UVA1603

作者:互联网

题目大意

  有一个由火柴棍组成的边长为n的正方形网格,每条边有n根火柴,共2n(n+1)根火柴。从上至下,从左到右给每个火柴编号,现在拿走一些火柴,问在剩下的后拆当中ongoing,至少还要拿走多少根火柴才能破坏掉所有的正方形?
image
  虽然本题的数据规模不大,但是却有多种选择火柴棍的方法,导致如果直接爆搜的话会炸,因此考虑采用IDA*算法。
  首先来看,我们该如何存储这个火柴棍图?
  个人比较喜欢把这样一个火柴棍图转化成这样的数组形式,存为square[][]
   0 1 0 1 0 1 0
   1 0 1 0 1 0 1
   0 1 0 1 0 1 0
   1 0 1 0 1 0 1
   0 1 0 1 0 1 0
   1 0 1 0 1 0 1
   0 1 0 1 0 1 0
   其中,0代表火柴棍交界的地方,1代表火柴棍。
  先给所有火柴棍编上号。在a上遍历,按序命名,用一个map<pair<int,int>,int> name进行映射
  之后,给每一个正方形编一个号,在用一个vector存一下每个正方形的所有边,便于进行搜索时快速确定本次该删除哪一条边。在存储边的同时,还要记录下当前这个正方形的原大小(即火柴棍全部摆满)和现在的大小(删除火柴棍后的数量),比较这两个的大小即可确定现在这个正方形是否被破坏。存储过程用函数实现

点击查看代码
void get(int x,int y,int len,int ccnt) {//搜正方形,并把组成正方形的每个火柴添加上当前的正方形 
	int tx = x,ty = y;
	for(ty = y; ty <= 2 * n + 1; ty++){//向右走 
		if(cnt == len){cnt = 0;break;}
		if(square[tx][ty]){
			cnt++;
			match[ccnt].push_back(name[make_pair(tx,ty)]);
		} 
	}
	for(tx = x; tx <= 2 * n + 1; tx++){//向下走 
		if(cnt == len){cnt = 0;break;}
		if(square[tx][ty]){
			cnt++;
			match[ccnt].push_back(name[make_pair(tx,ty)]);
		} 
	}
	for(ty; ty >= 1; ty--){//向左走 
		if(cnt == len){cnt = 0;break;}
		if(square[tx][ty]){
			cnt++;
			match[ccnt].push_back(name[make_pair(tx,ty)]);
		}
	}
	for(tx; tx >= 1; tx--){
		if(cnt == len){cnt = 0;break;}
		if(square[tx][ty]){
			cnt++;
			match[ccnt].push_back(name[make_pair(tx,ty)]);
		}
	} 
}
  IDA*的关键就在于估价函数,这个题该如何来写估价函数呢?   理想状况下,破坏一个正方形,可以顺带把这个正方形周围的正方形全部破坏(这就是估价函数和搜索函数check函数不同的原因,tmp当然就是来记录最理想状况的),当然,只是理想状况。如果按照这种方式进行破坏也不能在规定时间内破坏完毕,那这样的方案一定不可行,直接剪枝。 搜索时,以没有被破坏的正方形为对象,遍历它的每一条边,然后挨个搜索即可

  在实现当中,可以看见我们使用了memcpy这个函数,它可以将一个数组内的值复制到另一个数组里面,挺方便的

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 22; 
int t,n;
bool square[MAXN][MAXN],use[MAXN * MAXN];//vis表示正方形i是否被破坏 ,use表示该火柴棍是否被使用 
int cnt,now,del; 
map<pair<int,int>,int> name;
bool found;
bool tmp[MAXN * MAXN];
vector<int> match[MAXN * MAXN];//编号i的正方形由哪些火柴棍组成 
void get(int x,int y,int len,int ccnt) {//搜正方形,并把组成正方形的每个火柴添加上当前的正方形 
	int tx = x,ty = y;
	for(ty = y; ty <= 2 * n + 1; ty++){//向右走 
		if(cnt == len){cnt = 0;break;}
		if(square[tx][ty]){
			cnt++;
			match[ccnt].push_back(name[make_pair(tx,ty)]);
		} 
	}
	for(tx = x; tx <= 2 * n + 1; tx++){//向下走 
		if(cnt == len){cnt = 0;break;}
		if(square[tx][ty]){
			cnt++;
			match[ccnt].push_back(name[make_pair(tx,ty)]);
		} 
	}
	for(ty; ty >= 1; ty--){//向左走 
		if(cnt == len){cnt = 0;break;}
		if(square[tx][ty]){
			cnt++;
			match[ccnt].push_back(name[make_pair(tx,ty)]);
		}
	}
	for(tx; tx >= 1; tx--){
		if(cnt == len){cnt = 0;break;}
		if(square[tx][ty]){
			cnt++;
			match[ccnt].push_back(name[make_pair(tx,ty)]);
		}
	} 
}
bool _check(int i){
    for(int j=0;j<match[i].size();++j){
        if(use[match[i][j]])
            return 0;
    }
    return 1;//没被破坏 
}
bool check(int i){
	for(int j=0;j<match[i].size();++j){
        if(tmp[match[i][j]])
            return 0;
    }
    return 1;
}
void init(){
	name.clear();
	for(int i = 1; i < MAXN*MAXN; i++)match[i].clear();
	memset(square,0,sizeof square);
	memset(use,0,sizeof use);
	memset(tmp,0,sizeof tmp);
}
int estimate(){
	int sum = 0;
	memcpy(tmp,use,sizeof(use));
	for(int i = 1; i <= now; i++){
		if(check(i)){
			sum++;
			for(int j=0;j<match[i].size();++j)
                tmp[match[i][j]]=1;
		}
	}
	return sum;
} 
void IDAstar(int x,int maxd){
    if(x+estimate()>maxd)return;
    for(int i=1;i<=now;++i){
        if(_check(i)){
            for(int j=0;j<match[i].size();++j){
                use[match[i][j]]=1;
                //v.push_back(id[i][j]);
				IDAstar(x+1,maxd);
				//v.pop_back();
                use[match[i][j]]=0;
                if(found)return;
            }
            return;
        }
    }
    found=1;
    return;
}
int main(){
	cin >> t;
	while(t--){
		init();
		cin >> n;
		bool flag = 0;
		cnt = now = 0;
		for(int i = 1; i <= 2 * n + 1; i++){//构造正方形图并给火柴棍编号 
			if(i % 2 == 0)flag = 1;
			for(int j = 1; j <= 2 * n + 1; j++){
				square[i][j] = flag;
				if(flag == 1){
					cnt++;
					name[make_pair(i,j)] = cnt;
				}
				
				flag = !flag;
			}
		}
		cnt = 0;
				
		for(int i = 1; i <= 2 * n + 1; i++){//寻找正方形 
			if(i % 2 == 0)continue; 
			for(int j = 1; j <= 2 * n + 1; j++){
				if(!square[i][j])continue;
				for(int len = 1; len <= n; len++){
					if((i + 2 * (len - 1) + 1 > 2 * n + 1) || (j + 2 * (len - 1) + 1 > 2 * n + 1))break;
					now++;
					get(i,j,len,now);
				}
				
			}
		}
		cin >> del;
		int a;
		for(int i = 1; i <= del; i++){
			cin >> a;
			use[a] = 1;
		}
		for(int i = estimate();;i++){
			found = 0;
			IDAstar(0,i);
			if(found){
				cout << i << "\n";
				break;
			}
		}
	}
}

标签:cnt,tx,破坏,int,UVA1603,ty,正方形,火柴
来源: https://www.cnblogs.com/CZ-9/p/16454038.html