poj3279 Fliptile【二进制枚举状态】

xiaoxiao2021-02-28  106

题目链接:http://poj.org/problem?id=3279 题意:有一个n*m的棋盘,上面 摆满了棋子,有的是白棋,有的是黑棋,问你能否通过翻转把他变成全为白色的棋子,翻转一个棋子,周围的棋子都变成相反的颜色,如果能则输出一个相应的矩阵,只不过每一位表示翻转的次数,总翻转次数要最少,如果不能就输出impossible 解析:如果是自己来玩这个游戏的话,肯定是,如果上一行是黑色的,那么我一定会翻下面的那个棋子,那么第一行如何翻,就能决定第二行怎么翻了,同理,就可以决定接下来的所有行怎么翻了,所以我们只需要枚举第一行的所有状态即可

#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int inf = 0x7fffffff; int a[15][15]; int ans[15][15]; int tmp[15][15]; int n,m; int dx[] = {0,-1,1,0,0}; int dy[] = {1,0,0,-1,0}; int getv(int x,int y) { int res = a[x][y]; for(int i=0;i<5;i++) { int tx = x+dx[i]; int ty = y+dy[i]; if(tx<0 || tx>=n ||ty<0 || ty>=m) continue; res += tmp[tx][ty]; } return res&1; } int work() { for(int i=1;i<n;i++) { for(int j=0;j<m;j++) { if(getv(i-1,j)) tmp[i][j] = 1; } } for(int i=0;i<m;i++) { if(getv(n-1,i)) return inf; } int res = 0; for(int i=0;i<n;i++) { for(int j=0;j<m;j++) res += tmp[i][j]; } return res; } int main(void) { while(~scanf("%d %d",&n,&m)) { for(int i=0;i<n;i++) { for(int j=0;j<m;j++) scanf("%d",&a[i][j]); } memset(ans,0,sizeof(ans)); int res = inf; for(int i=0;i<1<<m;i++) { memset(tmp,0,sizeof(tmp)); for(int j=0;j<m;j++) tmp[0][j] = i>>j&1; int tt = work(); if(tt<res) { res = tt; for(int i=0;i<n;i++) { for(int j=0;j<m;j++) ans[i][j] = tmp[i][j]; } } } if(res==inf) { puts("IMPOSSIBLE"); continue; } for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { if(j)printf(" "); printf("%d",ans[i][j]); } puts(""); } } return 0; }
转载请注明原文地址: https://www.6miu.com/read-39576.html

最新回复(0)