细节决定成败,代码 尤其更甚!
POJ 1753 Flip Game:http://poj.org/problem?id=1753
题目大意 : 4X4的棋盘上随机摆放了黑或白朝上的棋子。 对任意一颗棋子翻面,其上下左右的棋子也会一同执行翻面操作
问,最少的反面次数,使得棋盘上所有棋子都为黑色或白色。
起初不能理解:一个棋盘上每个棋子只能翻一次,翻偶数次等于没有翻,这句话。
后来把思维掰回这个位置。。
后来又有一种错误的思考: 棋盘是4X4,则第一次有16个地方可以翻,第二次有15个地方可以翻,....,所以一共有 16 的阶乘次翻法,搜索次数已经爆炸了....O__O "…
看了看网上的讨论,恍然大悟.. 要搜索的次数是 翻棋的位置的 组合! 而不是排列。而16 的阶乘次,恰恰是16个点的排列,而不是选取组合的操作。
也就是说,总共搜索的次数最多 为2^16次,也就是65536.
选择DFS,思路很清晰:
从第一个点开始,翻或不翻,递归下一个点
每一次棋盘的情况都次保存下来岂不是大得很?
将16位展开用16位的字符串表示棋子颜色,(写博客时意识到不用也可以的,因为我用的是DFS,写的时候复杂化 了)
因为是DFS,所以只要对满足题意的翻动次数与 记录的ans值取较小就好了
错了一次,因为递归越界终止条件应该置于更新答案后面才对....
其实就是暴力搜索的DFS,用DFS什么位压缩都不用见鬼去吧。。。
DFS:
#include"cstdio"
#include"cstring"
#include"queue"
#include"iostream"
#include"algorithm"
using namespace std;
#define inf 109
#define loop(x,y,z) for(x=y;x<z;x++)
int ans=inf;
int pos[16];
int change[5]={0,4,-4,1,-1};
int book[4][4];
int pan(int n,int m)
{
if(n+m<0||n+m>=16)return 0;
int t=n%4;
if(t==0&&m==-1)return 0;
else if(t==3&&m==1)return 0;
return 1;
}
void dfs(int t,int sum,int step)
{
if(sum==0||sum==16)
{
ans=min(ans,step);
return;
}
if(t==16)return;
dfs(t+1,sum,step);
int i;
loop(i,0,5)
{
int j=change[i];
if(pan(t,j))
{
if(pos[t+j]=='1'){pos[t+j]='0';sum--;}
else {pos[t+j]='1';sum++;}
}
}
dfs(t+1,sum,step+1);
loop(i,0,5)
{
int j=change[i];
if(pan(t,j))
{
if(pos[t+j]=='1')pos[t+j]='0';
else pos[t+j]='1';
}
}
}
int main()
{
int i,j;
char a[5][5];
int sum=0;
loop(i,0,4)
scanf("%s",&a[i]);
loop(i,0,4)
loop(j,0,4)
{
int t=i*4+j;
if(a[i][j]=='w'){pos[t]='1';sum++;}
else pos[t]='0';
}
dfs(0,sum,0);
if(ans==inf)printf("Impossible\n");
else printf("%d\n",ans);
return 0;
}