poj1753 Flip Game

题意:4*4的正方形,每个格子有黑白两面,翻转格子使得4*4个格子显示全黑或全白,翻转要求:选中的那个格子,以及其上下左右相邻的格子(如果存在)要同时翻转。输出最小的达到要求的翻转次数或者Impossible(如果不可能)

题目链接:http://poj.org/problem?id=1753

分析:因为每个格子只有黑白两面,所以对于每个格子来说,要么不翻转,要么翻转一次,因为翻转奇数次结果和翻转一次得到的效果是一样的,而翻转偶数次得到的效果和不翻转是一样的,则总共有16个格子,最多要翻转16次,每个格子有黑白两种颜色,假设每一次面临的4*4正方形代表一个状态,则总共有2^16种状态,可以用16位二进制数表示,每一位1代表'b'(白),0代表'w'(黑)。当状态为(0或者65535)时则达到要求。

注意:1.因为只用求最少次数,用bfs做,将每一个没有访问到的状态 (用vis[]数组标记) 加入到队列中,如果游戏无法完成,状态必定会形成循环,由于重复状态不会再次入队,所以最后的队列一定会是空队列。当队列为空时说明此时还未达到要求,则是Impossible

        2.二进制运算,翻转某一个格子即指将1变成0,0变成1.这里可以用异或运算的性质,1^0=1,0^0=0;所以只用将需要翻转的那个格子对应的16位二进制数的位置为1,其他不翻转的格子对应的16位二进制数的位置为0得到一个数和当前状态的16位二进制数异或即可得到翻转后的状态。

例如:

bwwb
bbwb
bwwb
bwww

   的状态可以表示为1001 1101 1001 1000 (二进制),如果我现在要翻转第一行第一个格子,则可以用此二进制数和1100 1000 0000 0000 异或,则可以得到下一个状态next=1001 1101 1001 1000 ^  1100 1000 0000 0000 = 0101 0101 1001 1000

即:

wbwb
wbwb
bwwb
bwww

可以得到转换每一个格子需要异或的二进制数(十进制表示):

int change[16] = {

51200,58368,29184,12544,

35968,20032,10016,4880,

2248,1252,626,305,

140,78,39,19

};

代码:

 1 int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};  
 2 void init()  
 3 {  
 4     int i,j,x,y,t,temp;  
 5     for(i=0;i<4;++i)  
 6     {  
 7         for(j=0;j<4;++j)  
 8         {  
 9             temp = 0;   
10             temp ^= (1<<(15 - ( i*4 + j )));  
11             for(t=0;t<4;++t)  
12             {  
13                 x = i + dir[t][0];  
14                 y = j + dir[t][1];  
15                 if(x<0 || y<0 || x>3 || y>3)  
16                     continue;  
17                 temp ^= (1<<((3-x)*4+3-y));  
18             }  
19             cout<<temp<<" ";  
20         }  
21         cout<<endl;  
22     }  
23 }  

完整代码1:(bfs+bit)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<queue>
 4 #include<cmath>
 5 #include<string>
 6 #include<cstring>
 7 #include<algorithm>
 8 #include<vector>
 9 using namespace std;
10 char m[4][4];
11 //int di[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
12 struct Node
13 {
14     int state,step;
15 }nod[100000];
16 int vis[100000];
17 /*
18 int change[16] =   //16种状态转换,对应4*4的翻子位置 方法2.直接异或得到状态
19 {
20      51200,58368,29184,12544,
21      35968,20032,10016,4880,
22      2248,1252,626,305,
23      140,78,39,19
24 };
25 */
26 int getChang(int stat,int x,int y)  //方法1.翻转需要翻转的格子
27 {
28     int tp=stat;
29     tp^=(1<<(15-x*4-y));
30     if(x>0) tp^=(1<<(15-(x-1)*4-y)); //
31     if(x<3) tp^=(1<<(15-(x+1)*4-y)); //
32     if(y>0) tp^=(1<<(15-x*4-y+1));  //
33     if(y<3) tp^=(1<<(15-x*4-y-1));  //
34     return tp;
35 }
36 int bfs(Node cur)
37 {
38     queue<Node>q;
39     q.push(cur);
40     Node next;
41     vis[cur.state]=1;
42 
43     while(!q.empty())
44     {
45         cur=q.front();
46         q.pop();
47         if(cur.state==0||cur.state==65535)  //判断是否全黑/全白
48             return cur.step;
49         for(int i=0;i<4;i++)
50         {
51             for(int j=0;j<4;j++)
52             {
53                 next.state=getChang(cur.state,i,j);  //按部得到状态
54                 //next.state=cur.state^change[i]; //直接异或得到状态 (循环要改为for(int i=0;i<16;i++) )
55                 next.step=cur.step+1;
56                 if(next.state==0||next.state==65535)
57                     return next.step;
58                 if(vis[next.state])  //是否已经入队过
59                     continue;
60                 q.push(next);
61                 vis[next.state]=1;
62             }
63         }
64     }
65     return -1;
66 }
67 int main()
68 {
69     memset(vis,0,sizeof(vis));
70     int tmp=0;
71     for(int i=0;i<4;i++)
72     {
73         cin>>m[i];
74         for(int j=0;j<4;j++)
75         {
76             if(m[i][j]=='b')
77                 tmp+=(1<<(15-4*i-j));
78         }
79     }
80     Node cur;
81     cur.state=tmp;
82     cur.step=0;
83     int ans=bfs(cur);
84     if(ans==-1)
85         printf("Impossible\n");
86     else
87         printf("%d\n",ans);
88     return 0;
89 }

 完整代码2:(dfs)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<queue>
 5 #include<vector>
 6 #include<map>
 7 #include<algorithm>
 8 #include<string>
 9 #include<cstring>
10 using namespace std;
11 int mp[10][10];
12 int step;
13 bool flag;
14 int judge()
15 {
16     for(int i=0;i<4;i++)
17         for(int j=0;j<4;j++)
18             if(mp[i][j]!=mp[0][0])
19                return 0;
20     return 1;
21 }
22 void flip(int x,int y)
23 {
24     mp[x][y]=!mp[x][y];
25     if(x>0) mp[x-1][y]=!mp[x-1][y];
26     if(x<3) mp[x+1][y]=!mp[x+1][y];
27     if(y>0) mp[x][y-1]=!mp[x][y-1];
28     if(y<3) mp[x][y+1]=!mp[x][y+1];
29 }
30 void dfs(int x,int y,int deep)
31 {
32     if(deep==step)
33     {
34         flag=judge();
35         return;
36     }
37     if(flag||x>=4)
38         return;
39     flip(x,y);
40     if(y<3)
41         dfs(x,y+1,deep+1);
42     else
43         dfs(x+1,0,deep+1);
44     flip(x,y);
45     if(y%4<3)
46         dfs(x,y+1,deep);
47     else
48         dfs(x+1,0,deep);
49     return;
50 }
51 int main()
52 {
53     string s;
54     flag=0;
55     for(int i=0;i<4;i++)
56     {
57         cin>>s;
58         for(int j=0;j<4;j++)
59             if(s[j]=='b')
60                mp[i][j]=1;
61     }
62     for(step=0;step<=16;step++)
63     {
64         dfs(0,0,0);
65         if(flag)
66             break;
67     }
68     if(flag)
69         printf("%d\n",step);
70     else
71         printf("Impossible\n");
72     return 0;
73 }
View Code

 

posted @ 2016-09-10 16:03  萌新的学习之路  阅读(172)  评论(0编辑  收藏  举报