标签:状态 操作 ace etc cti str 搜索 amp 复杂度
给出一个\(5\times 5\)矩形网格图,\(a[i][j]\)表示第i行第j列的数字(只能为0或者1),每次操作可以选择一个位置,对于该个位置以及其上下左右个一个位置上的数字0变成1,1变成0,询问是否能少于6次将所有数字变为1,如果能,请输出最少次数。
其实最终变为0还是变为1都无所谓,不妨把网格图中所有数字取反,这样就转换成最后数字要全部变为1,这样方便一些(接下来的行列坐标从0开始)。
设\(h[i]\)为第i行的状态(第k位上1表示表示\(a[i][k]=1\),反之)。
注意到问题的异或性,不妨将这类问题称作类异或问题,这样的问题具有一个通性,即异或的交换律和结合律它也满足,于是多次进行一个位置的操作没有意义,而且操作不存在顺序,这样会大大优化我们的搜索。
因为原题是存在多组数据,而且数据组数还很多,于是接下来直接暴力组合
\(O(C_{25}^6)=177100\),会超时
超时代码
#include <iostream>
#include <cstdio>
#define il inline
#define ri register
using namespace std;
int ans,li((1<<25)-1);
il void get(char&);
void dfs(int,int,int);
template<class free>
il free Min(free,free);
int main(){char c;
int lsy,s;scanf("%d",&lsy);
while(lsy--){s=0;
for(int i(0);i<25;++i)
get(c),s|=c-48<<i;
ans=7,dfs(0,0,s);
if(ans==7)puts("-1");
else printf("%d\n",ans);
}
return 0;
}
il void get(char&c){
while(c=getchar(),c==' '||c=='\n'||c=='\r');
}
template<class free>
il free Min(free a,free b){
return a<b?a:b;
}
void dfs(int a,int b,int c){
if(b>=ans)return;
if(a==25){
if(c==li)ans=Min(ans,b);
return;
}
dfs(a+1,b,c),c^=(1<<a);
if(a%5)c^=(1<<a-1);
if(a%5<4)c^=(1<<a+1);
if(a-5>=0)c^=(1<<a-5);
if(a+5<25)c^=(1<<a+5);
dfs(a+1,b+1,c);
}
于是我们接下来的搜索要考虑剪支,因为是网格图问题,考虑方向有行列,对角线和矩形,我们按行处理,这样我们每一行只要枚举\(2^5=32\)次,不妨用枚举二进制代替自由组合,显然时间复杂度\(O(32^5)=33554432\),加上最优性剪支,即如果超出6或者比最优解大,那么return,这样还不够,注意到我们是按行处理的,如果处理完这一行,下一行一定要将其变为0,否则它以后再也变不回0了,于是加上这个剪支,此题才能过。
参考代码:
#include <iostream>
#include <cstdio>
#define il inline
#define ri register
using namespace std;
int ans,jm[6],tot[32];
il void get(char&);
void dfs(int,int,int,int);
int main(){char c;
int lsy;scanf("%d",&lsy);
for(int i(0),j;i<32;++i)
for(j=4;j>=0;--j)
if(i>>j&1)++tot[i];
while(lsy--){ans=7;
for(int i(0),j;i<5;++i)
for(j=0,jm[i]^=jm[i];j<5;++j)
get(c),(c-=48)^=1,jm[i]|=c<<j;
dfs(0,0,jm[0],0);
if(ans==7)puts("-1");
else printf("%d\n",ans);
}
return 0;
}
void dfs(int h,int l,int r,int c){
if(c>=ans)return;
if(h==5){if(!l)ans=c;return;}
for(int i(0),j,k;i<32;++i){
if(h&&i^l)continue;k=r;
for(j=4;j>=0;--j)
if(i>>j&1){k^=1<<j;
if(j)k^=1<<j-1;
if(j<4)k^=1<<j+1;
}dfs(h+1,k,jm[h+1]^i,c+tot[i]);
}
}
il void get(char &c){
while(c=getchar(),c==' '||c=='\n'||c=='\r');
}
标签:状态 操作 ace etc cti str 搜索 amp 复杂度
原文地址:https://www.cnblogs.com/a1b3c7d9/p/11204293.html