1. 程式人生 > >【LuoguP2576】夢幻摺紙(ZJOI2005)-思維

【LuoguP2576】夢幻摺紙(ZJOI2005)-思維

測試地址:夢幻摺紙
做法: 本題需要用到思維。
考慮最後折出來的正方形,從上到下的各層中,有可能有兩層在前後側相連,也有可能有兩層在左右側相連。易知,無論怎麼折前後側的相連都不會成為左右側,這啟發我們分開判斷兩維是不是成立。
要判斷某一維是不是成立,需要觀察出下面兩個結論:
1.如果兩列 i , j i,j

相鄰,最後所有 a ( x , i ) a(x,i) a
( x , j ) a(x,j)
相連的側向是相同的。
2.如果三列 i , j
, k i,j,k
中, i , j i,j 相鄰, j , k j,k 相鄰,那麼最後 a ( x , i ) a(x,i) a ( x , j ) a(x,j) 相連的側向,與 a ( x , j ) a(x,j) a ( x , k ) a(x,k) 相連的側向是相反的。
有了這個結論,我們就能知道這一維度上的元素之間的相連側向,然後我們用個棧來判斷它是不是合法的就行了,把上面結論中的行列交換也是一樣的,於是我們就解決了這一題。
以下是本人程式碼:

#include <bits/stdc++.h>
using namespace std;
int T,n,m,a[110][110],tot;
int con[10010][2],st[10010][2],top[2];

bool check()
{
	top[0]=top[1]=0;
	for(int i=1;i<=n*m;i++)
	{
		if (con[i][0]<0&&st[top[0]][0]!=-con[i][0])
			return 0;
		if (con[i][0]<0) top[0]--;
		if (con[i][0]>0) st[++top[0]][0]=con[i][0];
		if (con[i][1]<0&&st[top[1]][1]!=-con[i][1])
			return 0;
		if (con[i][1]<0) top[1]--;
		if (con[i][1]>0) st[++top[1]][1]=con[i][1];
	}
	return 1;
}

int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
				scanf("%d",&a[i][j]);
	
		tot=0;
		memset(con,0,sizeof(con));
		for(int i=1;i<n;i++)
			for(int j=1;j<=m;j++)
			{
				tot++;
				int x=min(a[i][j],a[i+1][j]),y=max(a[i][j],a[i+1][j]);
				con[x][i&1]=tot;
				con[y][i&1]=-tot;
			}
		
		if (!check()) {printf("Cheat\n");continue;}
	
		tot=0;
		memset(con,0,sizeof(con));
		for(int j=1;j<m;j++)
			for(int i=1;i<=n;i++)
			{
				tot++;
				int x=min(a[i][j],a[i][j+1]),y=max(a[i][j],a[i][j+1]);
				con[x][j&1]=tot;
				con[y][j&1]=-tot;
			}
		
		if (!check()) {printf("Cheat\n");continue;}
		printf("AllRight\n");
	}
	
	return 0;
}