POJ3279

来源:互联网 发布:java jdbc delete 编辑:程序博客网 时间:2024/05/16 01:37

做过很多遍的二进制搜索,每次写就是对着代码敲一遍,然后下次写又不会


链接:http://poj.org/problem?id=3279

题意:n*m的矩阵,全是0和1构成的,当选择翻一个点的时候,周围的点会受到影响,问选择翻n*m矩阵中的哪些点,可以将所有点均翻过来?


为什么要用搜索?因为n和m很小,最大是15

为什么要用二进制搜索?因为是枚举状态,而且是每行每列的状态

怎么样枚举最好?枚举第一行,然后依次遍历其他行,枚举第一行的复杂度是2的n次方,然后遍历全矩阵式n*m,整个复杂度相乘没有问题


怎么搜索呢?

用一个整数表示1行的状态,比如255=11111111(2),那么循环就是从0到255表示256种情况,255的第0位至第7位均是1,所以呢,表示全部需要翻,然后从第二行到第n-1行依次推理得需要或者不需要翻,再用最后一行来检验方案是不是可行


const int maxn=20;const int inf=0x3f3f3f3f;int n,m;int mp[maxn][maxn];int mem[maxn][maxn];int ans[maxn][maxn];int mx[]={0,0,1,-1};int my[]={1,-1,0,0};bool ok(int x,int y){if (x<0||y<0||x>=m||y>=n) return false;return true;}bool calc(int x,int y){int ret=mp[x][y]+mem[x][y];for(int i=0;i<4;i++){int tx=x+mx[i];int ty=y+my[i];if (ok(tx,ty)) ret+=mem[tx][ty];}return ret%2; }void nxt(int x,int y,int &tx,int &ty){tx=x;ty=y+1;if (ty==n){++tx;ty=0;}}int dfs(int x,int y,int num){if (x==m) return num;bool tem=calc(x-1,y);if (tem){mem[x][y]=true;++num;}int tx,ty;nxt(x,y,tx,ty);return dfs(tx,ty,num);}int search(int in){memset(mem,false,sizeof(mem));int ret=0;for(int i=0;i<n;i++)if ((in>>i)&1){mem[0][i]=true;++ret;}ret+=dfs(1,0,0);for(int i=0;i<n;i++)if (calc(m-1,i)) return inf;return ret;}int main(){//freopen("input.txt","r",stdin);while(scanf("%d%d",&m,&n)!=EOF){for(int i=0;i<m;i++)for(int j=0;j<n;j++) scanf("%d",&mp[i][j]);int tem=inf;for(int i=0;i<(1<<n);i++){int rec=search(i);if (tem>rec){tem=rec;memcpy(ans,mem,sizeof(mem));}}if (tem==inf){puts("IMPOSSIBLE");continue;}for(int i=0;i<m;i++)for(int j=0;j<n;j++)printf("%d%c",ans[i][j],j==n-1?'\n':' ');}return 0;}


0 0
原创粉丝点击