POJ2965 The Pilots Brothers' refrigerator

参考高手的高效解法:
> 证明:要使一个为'+'的符号变为'-',必须其相应的行和列的操作数为奇数;可以证明,如果'+'位置对应的行和列上每一个位置都进行一次操作,则整个图只有这一'+'位置的符号改变,其余都不会改变.
> 设置一个4*4的整型数组,初值为零,用于记录每个点的操作数,那么在每个'+'上的行和列的的位置都加1,得到结果模2(因为一个点进行偶数次操作的效果和没进行操作一样,这就是楼上说的取反的原理),然后计算整型数组中一的
> 个数即为操作数,一的位置为要操作的位置(其他原来操作数为偶数的因为操作并不发生效果,因此不进行操作)
*********************************
此上证其可以按以上步骤使数组中值都为‘-’
********************************
在上述证明中将所有的行和列的位置都加1后,在将其模2之前,对给定的数组状态,将所有的位置操作其所存的操作数个次数,举例,如果a[i][j]==n,则对(i,j)操作n次,当所有的操作完后,即全为‘-’的数组。
其实就是不模2的操作,作了许多的无用功。
以上的操作次序对结果无影响,如果存在一个最小的步骤,则此步骤一定在以上操作之中。(简单说下:因为以上操作已经包含了所有可改变欲改变位置的操作了)
而模2后的操作是去掉了所有无用功之后的操作,此操作同样包含最小步骤。
但模2后的操作去掉任何一个或几个步骤后,都不可能再得到全为‘-’的。(此同样可证明:因为操作次序无影响,先进行最小步骤,得到全为‘-’,如果还剩下m步,则在全为‘-’的数组状态下进行这m步操作后还得到一个全为
‘-’的数组状态,此只能是在同一个位置进行偶数次操作,与前文模2后矛盾,所以m=0),因此模2后的操作即为最小步骤的操作。

 

 

 1 #include<cstdio>
2 #include<string.h>
3 using namespace std;
4 int mat[4][4]={0};
5 void change(int i,int j)
6 {
7 for(int t=0;t<4;t++)
8 mat[i][t]=(mat[i][t]+1)%2;
9 for(int t=0;t<4;t++)
10 if(t!=i)
11 mat[t][j]=(mat[t][j]+1)%2;
12 }
13 int main()
14 {
15 int n=0,x[16],y[16];
16 char s[5][5];
17 for(int i=0;i<4;i++)
18 scanf("%s",s[i]);
19 for(int i=0;i<4;i++)
20 for(int j=0;j<4;j++)
21 if(s[i][j]=='+')
22 change(i,j);
23 for(int i=0;i<4;i++)
24 for(int j=0;j<4;j++)
25 if(mat[i][j]==1)
26 {
27 x[n]=i+1;y[n]=j+1;n++;
28 }
29 printf("%d\n",n);
30 for(int i=0;i<n;i++)
31 printf("%d %d\n",x[i],y[i]);
32 return 0;
33 }

 

用深搜+位运算做的,change数组可以预先算好,也可以让计算机自己算。每次在调用search(square,dep,base)的时候判断square是否已经满足,满足则将此时的x,y数组赋值给记录最优点集的bx,by。最多的深度是到16,因为change的次数最多为16次,多于16或者大于等于找到的最小step再继续递归下去都是无意义的,所以返回。

枚举从base(最初调用为0)开始,tsquare是棋盘在i位置change的情况,调用search(tsquare^change[i],dep+1,i+1); 循环结束则是调用了searchsearch(square,dep,base)的结束,所以枚举了base从0到16,有change和没有change的所有情况。

 1 #include<cstdio>
2 #include<string.h>
3 using namespace std;
4 int p[16];
5 //int change[16]={010437,021057,042117,0104217,010761,021362,042364,0104370,017421,027442,047504,0107610,0170421,0171042,0172104,0174210};
6 int change[16]={0};
7 int x[16],y[16];
8 int bx[16],by[16];
9 int step=17;
10 void search(int square,int dep,int base)
11 {
12 if(square==0)
13 {
14 if(dep<step)
15 step=dep;
16 for(int i=0;i<16;bx[i]=x[i],by[i]=y[i],i++);
17 return;
18 }
19 if(dep>=step) return;
20
21 for(int i=base;i<16;i++)
22 {
23 int tsquare=square;
24 tsquare^=change[i];
25 x[dep]=i/4+1;y[dep]=i%4+1;
26 search(tsquare,dep+1,i+1);
27 }
28 }
29 int main()
30 {
31 int square=0;
32 char x;
33 for(int i=0;i<16;i++) p[i]=(1<<i);
34 for(int i=0;i<16;i++)
35 {
36 int px=i/4,py=i%4;
37 for(int k=0;k<4;k++)
38 {
39 if(k==px) continue;
40 change[i]+=p[k*4+py];
41 }
42 for(int k=0;k<4;k++)
43 change[i]+=p[px*4+k];
44 }
45 for(int i=0;i<16;)
46 {
47 x=getchar();
48 if(x=='+')
49 square+=p[i++];
50 else if(x=='-') i++;
51 else continue;
52 }
53 search(square,0,0);
54 printf("%d\n",step);
55 for(int i=0;i<step;i++)
56 printf("%d %d\n",bx[i],by[i]);
57 }

 

你可能感兴趣的:(poj)