题意:
给定一个火柴棒拼成的方格阵,然后去掉一些火柴棒,问至少再去掉几根火柴棒能够让图中一个正方形都没有。
思路:
1. 由于题目中给定了 n 的范围,2 * n * (n + 1) <= 60 -> 所以能够保证所有的火柴用 long long的位运算表示;
2. 启发式函数 h 的计算需要考量:如果删除了某个方阵的一个边,则能够保证 h(s1) <= h(s2) + C(s1, s2),其中 C(s1, s2) = 1,h(s1) - h(s2) <= 1;
3. 各种位运算的范围要明确,如 1<<i 前面要加上long long 修饰方能得到正确的结果
代码:
#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;const int INFS = 0x7fffffff;int N,C,E,bound;long long squ[100],xiao[6][6];bool flag;long long get2(int i){ return ((long long)1<<(i-1));}int getnumber1(int i,int j){ return (2*N+1)*(i-1)+j;}int getnumber2(int i,int j){ return (2*N+1)*(i-1)+j+N;}void build(){ C=0; memset(xiao,0,sizeof(xiao)); int i,j; for(i=1;i<=N;i++) for(j=1;j<=N;j++) { xiao[i][j]|=get2(getnumber1(i,j))|get2(getnumber1(i+1,j)); xiao[i][j]|=get2(getnumber2(i,j))|get2(getnumber2(i,j+1)); squ[C++]=xiao[i][j]; } for(int size=2;size<=N;size++) { for(i=1;i+size-1<=N;i++) { for(j=1;j+size-1<=N;j++) { squ[C]=0; for(int a=0;a<size;a++) { for(int b=0;b<size;b++) { squ[C]^=xiao[i+a][j+b];; } } C++; } } }}int dfs(long long state,int de){ int h=0; long long u=0,s=state; for(int i=0;i<C;i++) { if((s&squ[i])==squ[i]) { h+=1; s^=squ[i]; if(u==0) u=squ[i]; } } if(h==0) { flag=true; return de; } if(de+h>bound) return de+h; int news=INFS; for(int i=1;i<=E;i++) { if(u&get2(i)) { int b=dfs(state^get2(i),de+1); if(flag) return b; news=min(b,news); } } return news;}int main(){ int t; scanf("%d",&t); while(t--) { scanf("%d",&N); build(); E=2*N*(N+1); int k; long long state=((long long)1<<E)-1; scanf("%d",&k); for(int i=0;i<k;i++) { int x; scanf("%d",&x); state^=get2(x); } flag=false; bound=0; while(!flag) { bound=dfs(state,0); } printf("%d\n",bound); }}
时间: 2024-12-29 13:05:01