您的位置:首页 > 其它

Ural_1403

2011-08-21 15:54 399 查看
定义如下图所示 所有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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: