1. 程式人生 > >bzoj 1647: [Usaco2007 Open]Fliptile 翻格子遊戲【dfs】

bzoj 1647: [Usaco2007 Open]Fliptile 翻格子遊戲【dfs】

div 枚舉 del lag 高斯 possible true void 一個

這個可以用異或高斯消元,但是我不會呀我用的暴搜
2的m次方枚舉第一行的翻轉情況,然後後面的就定了,因為對於一個j位置,如果i-1的j位置需要翻,那麽一定要翻i的j,因為這是i-1的j最後翻的機會
按字典序搜索然後取次數min即可

#include<cmath>  
#include<cstdio>  
#include<cstring>  
#include<iostream>  
#include<algorithm>  
using namespace std;  
const int N=20,inf=1707185547;  
int
n,m,f[N][N],ans[N][N],p[N][N],a[N][N],mn=inf; void dfs(int x) { if(x>m) { for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) p[i][j]=a[i][j]; for(int i=1;i<=m;i++) if(f[1][i]) { p[1
][i]^=1,p[2][i]^=1; p[1][i+1]^=1,p[1][i-1]^=1; } for(int i=2;i<=n;i++) for(int j=1;j<=m;j++) { if(p[i-1][j]==1) { f[i][j]=1; p[i][j]^=1
; p[i][j+1]^=1,p[i][j-1]^=1; p[i+1][j]^=1,p[i-1][j]^=1; } else f[i][j]=0; if(p[i-1][j]) return; } bool flag=false; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(p[i][j]) { flag=true; break; } if(!flag) { int tot=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(f[i][j]) tot++; if(tot>=mn) return; mn=tot; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) ans[i][j]=f[i][j]; } return; } for(int i=0;i<=1;i++) { f[1][x]=i; dfs(x+1); } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); dfs(1); if(mn==inf) printf("IMPOSSIBLE"); else { for(int i=1;i<=n;i++) { for(int j=1;j<m;j++) printf("%d ",ans[i][j]); printf("%d\n",ans[i][m]); } } return 0; }

bzoj 1647: [Usaco2007 Open]Fliptile 翻格子遊戲【dfs】