Ural_1403

定义如下图所示 所有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;
}


你可能感兴趣的:(Ural_1403)