定义如下图所示 所有1构成一个折角(对角线上的一点即它正上方和正左方的点) 则图中一共有2*n+1个折角(N=2)
00100
00100
11100
00000
00000
每两次改变可以改变一个矩形的四个角,以(1,1)为左上角,将所有加号除第一行或和第一列外的位置全部变成减号,,如下图
10110
10000
10000
00000
这时每个折角最多有两个加号,改变有两个加号的折角,使这个加号移到对角线上,这样每个折角就最多就只剩一个了,
10010
10000
00100
00000
一共只有2*n+1个折角,加号的个数不会超过2n+1个
因为每次更改都是更改偶数个(4个),所以加号个数的奇偶性不会改变,所以只要一开始是偶数个加号,那么最后至多就只有2*n个
如果一开始是奇数,更改对角线使加号变成偶数个(对角线上有奇数个点,更改后必然更改加号个数奇偶性)
#include <cstdio> #include <string> #include <math.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> using namespace std; int n,ar[50][50],ans[50]; void initans(int r1,int r2,int c1,int c2){ ans[r1]=c1,ans[r2]=c2; int t=1; ar[r2][c2]=(ar[r2][c2]==1?0:1); ar[r1][c1]=(ar[r1][c1]==1?0:1); for(int i=1;i<=2*n+1;i++){ if(i==r1||i==r2)continue; if(t==c1||t==c2)t++; if(t==c1||t==c2)t++; ans[i]=t; t++; } } void printans(){ for(int i=1;i<=2*n;i++)printf("%d ",ans[i]); printf("%d\n",ans[2*n+1]); } /* 00100 定义如右图所示 所有1构成一个折角 则图中一共有2*n+1个折角(N=2) 00100 构造 使每个折角上只有一个加号 11100 每两次改变可以改变一个矩形的四个角,以(1,1)为左上角,将所有加号移到第一行或者第一列 00000 这时每个折角最多有两个加号,同样改变矩形顶角将这个加号移到对角线上,这样每个折角就只剩一个了, 00000 因为每次更改都是更改偶数个(4个),所以加号个数的奇偶性不会改变,所以只要一开始是偶数个加号,那么最后至多就只有2*n个 如果一开始是奇数,更改对角线使加号变成偶数个(对角线上有奇数个点,更改后必然更改加号个数奇偶性) */ int main(){ scanf("%d",&n); char line[50]; int ons=0; for(int i=1;i<=2*n+1;i++){ scanf("%s",line+1); for(int j=1;j<=2*n+1;j++){ ar[i][j]=(line[j]=='+'?1:0); if(ar[i][j]==1)ons++; } } //必有解 printf("There is solution:\n"); //折到第一列和第一行 if(ons%2==1){ for(int i=1;i<=2*n+1;i++){ ar[i][i]=(ar[i][i]==1?0:1); printf("%d",i); if(i!=2*n+1)printf(" "); } printf("\n"); } for(int i=2;i<=2*n+1;i++){ for(int j=2;j<=2*n+1;j++){ if(ar[i][j]==1){ initans(1,i,1,j); printans(); initans(1,i,j,1); printans(); } } } //使每一个折角上顶多有1个加号 for(int i=2;i<=2*n+1;i++){ if(ar[i][1]&&ar[1][i]){ initans(1,i,i,1); printans(); initans(1,i,1,i); printans(); } } system("pause"); return 0; }