POJ3279 Fliptile
(一个需要小技巧的爆搜题)
思路:通过观察可以发现,当我们确定了第一行各个位置翻或不翻后,在处理第二行时,第二行每个位置翻或不翻应该是固定的,因为若想使第一行全变白,有且仅有第二行可以做到。以此类推,除第一行外,其余每行翻或不翻都是确定的。我们仅需暴力枚举第一行每个位置是否翻,然后处理其余每行。
需要注意的是:在我们处理完m-1行后,需扫一遍最后一行是否已全变为白色,若是,则可用于更新答案。
题目还要求该答案的字典序最小,我们可发现一种方案只与第一行有关,所以在dfs枚举第一行时,我们需先枚举不翻,再枚举翻(因为不翻是0,翻是1),如此便解决了题目要求字典序最小的要求。
代码实现:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define maxn 1010
#define ll long long
#define clear(a) memset(a,0,sizeof a)
int n,m,sum,ans=1e7;
int lazy[maxn];
int mp[maxn][maxn],pre[maxn][maxn],ppsave[maxn][maxn];
int psave[maxn][maxn],save[maxn][maxn];
int check(){
int c=1;
for(int i=1;i<=n;i++)
if(pre[m][i])c=0;
return c;
}
void solve(){
int sta=sum;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
ppsave[i][j]=psave[i][j];
for(int i=1;i<=n;i++){
if(lazy[i]==1){
if(pre[1][i]==1)pre[1][i]=0;
else pre[1][i]=1;
if(pre[1][i+1]==1)pre[1][i+1]=0;
else pre[1][i+1]=1;
if(pre[1][i-1]==1)pre[1][i-1]=0;
else pre[1][i-1]=1;
if(pre[2][i]==1)pre[2][i]=0;
else pre[2][i]=1;
}
else continue;
}
for(int i=2;i<=m;i++){
for(int j=1;j<=n;j++){
if(pre[i-1][j]){
sum++;
psave[i][j]++;
pre[i-1][j]=0;
if(pre[i][j]==1)pre[i][j]=0;
else pre[i][j]=1;
if(pre[i+1][j]==1)pre[i+1][j]=0;
else pre[i+1][j]=1;
if(pre[i][j+1]==1)pre[i][j+1]=0;
else pre[i][j+1]=1;
if(pre[i][j-1]==1)pre[i][j-1]=0;
else pre[i][j-1]=1;
}
else continue;
}
}
if(ans>sum&&check()){
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
save[i][j]=psave[i][j];
ans=sum;
}
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
psave[i][j]=ppsave[i][j];
sum=sta;
}
void dfs(int x){
if(x>n){
if(sum>ans)return;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
pre[i][j]=mp[i][j];
solve();
return;
}
for(int i=0;i<=1;i++){
lazy[x]=i;
if(i==1){
sum++;
psave[1][x]++;
}
dfs(x+1);
if(i==1){
sum--;
psave[1][x]--;
}
}
}
int main(){
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
scanf("%d",&mp[i][j]),pre[i][j]=mp[i][j];
dfs(1);
if(ans>=1000){
printf("IMPOSSIBLE\n");
return 0;
}
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++)
printf("%d ",save[i][j]);
printf("\n");
}
return 0;
}