POJ1753-FlipGame
第一种方法:先枚举第一行的16种情况,然后依次翻转第2、3、4行分别使上一行为同一色,然后判断第四行,若仍为同一色,则比较翻转次数;否则Impossible.
Problem: 1753 | User: wjinkun | |
Memory: 352K | Time: 16MS | |
Language: GCC | Result: Accepted |
1 #include <stdio.h>
2 #include <string.h>
3
4 int piece[4][4],temp_piece[4][4];
5
6 void flip(int i,int j)
7 {
8 temp_piece[i][j]=!temp_piece[i][j];
9
10 if(i-1>=0)
11 temp_piece[i-1][j]=!temp_piece[i-1][j];
12
13 if(i+1<=3)
14 temp_piece[i+1][j]=!temp_piece[i+1][j];
15
16 if(j-1>=0)
17 temp_piece[i][j-1]=!temp_piece[i][j-1];
18
19 if(j+1<=3)
20 temp_piece[i][j+1]=!temp_piece[i][j+1];
21 }
22
23 int main()
24 {
25 int i,j,k,min=17,n;
26
27 for(i=0; i<4; i++) //b1w0
28 {
29 for(j=0; j<4; j++)
30 if(getchar()=='b')
31 piece[i][j]=1;
32 else
33 piece[i][j]=0;
34
35 getchar();
36 }
37
38 //全翻至白
39 for(i=0; i<16; i++) //第一行2^4=16种情况
40 {
41 memcpy(temp_piece,piece,sizeof(piece));
42 n=0;
43
44 for(j=0; j<4; j++)
45 if((i&(1<<j))>>j) //第一行第j个翻转
46 {
47 flip(0,j);
48 n++;
49 }
50
51 for(j=1; j<4; j++) //翻转第2.3.4行分别使上一行为都为白
52 for(k=0; k<4; k++)
53 if(temp_piece[j-1][k])
54 {
55 flip(j,k);
56 n++;
57 }
58
59 for(j=0; j<4; j++) //检查第4行是否都为白
60 if(temp_piece[3][j])
61 {
62 n=17;
63 break;
64 }
65
66 if(n<min)
67 min=n;
68 }
69
70 //全翻至黑
71 for(i=0; i<16; i++)
72 {
73 memcpy(temp_piece,piece,sizeof(piece));
74 n=0;
75
76 for(j=0; j<4; j++)
77 if((i&(1<<j))>>j)
78 {
79 flip(0,j);
80 n++;
81 }
82
83 for(j=1; j<4; j++)
84 for(k=0; k<4; k++)
85 if(!temp_piece[j-1][k])
86 {
87 flip(j,k);
88 n++;
89 }
90
91 for(j=0; j<4; j++)
92 if(!temp_piece[3][j])
93 {
94 n=17;
95 break;
96 }
97
98 if(n<min)
99 min=n;
100 }
101
102 if(n!=17)
103 printf("%d\n",min);
104 else
105 printf("%s","Impossible\n");
106
107 return 0;
108 }
第二种方法是看了别人的思路后写的,枚举+bfs:用unsigned short记录棋子的2^16=65536种情况,将初始状态入队列,再出队列判断是否是0或65535(同一色),若是则输出,否则将由该状态翻转1次的入队列,依次类推。关键减少时间的步骤是要记录最大的棋子,比如a状态由翻转2,5两个棋子得到,那么a的下一次翻转只需从6开始,前面的情况一定出现过,因此需记录5,减少重复。
Problem: 1753 | User: wjinkun | |
Memory: 588K | Time: 16MS | |
Language: GCC | Result: Accepted |
1 #include <stdio.h> 2 unsigned short queue[65536][2]; //[0]记录状态,[1]记录下一次起始位置 3 unsigned short step[65536]; //步数 4 5 int main() 6 { 7 int rear=1,top=0,i,j,temp; 8 9 for(i=0; i<4; i++) //b1w0 10 { 11 for(j=0; j<4; j++) 12 if(getchar()=='b') 13 queue[0][0]|=1<<(i*4+j); 14 15 getchar(); 16 } 17 18 19 while(rear>top) 20 { 21 if(queue[top][0]==0||queue[top][0]==65535) 22 { 23 printf("%d\n",step[queue[top][0]]); 24 return 0; 25 } 26 else 27 { 28 for(i=queue[top][1]; i<16; i++) 29 { 30 temp=queue[top][0]; 31 temp^=1<<i; 32 33 if(i%4!=0) 34 temp^=1<<(i-1); 35 36 if(i%4!=3) 37 temp^=1<<(i+1); 38 39 if(i-4>=0) 40 temp^=1<<(i-4); 41 42 if(i+4<16) 43 temp^=1<<(i+4); 44 45 queue[rear][0]=temp; 46 queue[rear++][1]=i+1; 47 step[temp]=step[queue[top][0]]+1; 48 } 49 50 top++; 51 } 52 } 53 54 printf("%s\n","Impossible\n"); 55 return 0; 56 }