【LuoguP2576】夢幻摺紙(ZJOI2005)-思維
阿新 • • 發佈:2018-11-07
測試地址:夢幻摺紙
做法: 本題需要用到思維。
考慮最後折出來的正方形,從上到下的各層中,有可能有兩層在前後側相連,也有可能有兩層在左右側相連。易知,無論怎麼折前後側的相連都不會成為左右側,這啟發我們分開判斷兩維是不是成立。
要判斷某一維是不是成立,需要觀察出下面兩個結論:
1.如果兩列
相鄰,最後所有
和
相連的側向是相同的。
2.如果三列
中,
相鄰,
相鄰,那麼最後
和
相連的側向,與
和
相連的側向是相反的。
有了這個結論,我們就能知道這一維度上的元素之間的相連側向,然後我們用個棧來判斷它是不是合法的就行了,把上面結論中的行列交換也是一樣的,於是我們就解決了這一題。
以下是本人程式碼:
#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;
}