題目大意
有一個n*m的網格圖,需要在每個格子內部填入A~C,要求滿足:
① 每個2*2的小方格都要有ABC
② 邊相鄰格子內字母不同
給出初始若干格子相同(滿足角相鄰)的限制,判斷是否存在合法解
2<=n,m<=2e3
題解
神必題……
首先假設給2*2的格子內角相鄰的相同格子連斜邊,則會連出一個圖,每個2*2格子內都要有一條連邊
然後在這個圖裏連通的都是同一個字母,所以會有一些連邊情況不合法,比如
這樣,則實際上外面四個圓圈都相等,所以會連一下,與右上的邊衝突
顯然所有連邊同向合法,然後根據觀察可得,將一個合法圖的斜邊進行任意行/列翻轉仍然合法
所以可以根據行/列是否翻轉設01狀態,然後用給出的限制來對行/列狀態連邊(相同/相異),最後dfs判斷是否有矛盾即可
證明:
可以設ABC對應012,然後對邊相鄰的格子連橫向/縱向的邊,邊權爲(上-下)%3 or (左-右)%3
然後觀察發現一個2*2格子內,上下和左右的邊權分別相等(確定一行/列的狀態,只能是1/2),且當正對角線相同時上下=左右,反對角線相同時上下≠左右
把差值1/2變成0/1,設爲行/列的權值;兩種邊決定行列權值相同/相異,則和上面差不多了
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define ll long long
#define file
using namespace std;
int T,n,m,K,i,j,k,l,x,y;
int X1,Y1,X2,Y2;
int a[80001][3],ls[40001],len;
int f[40001];
bool ans;
void New(int x,int y,int z)
{
++len;
a[len][0]=y;
a[len][1]=ls[x];
ls[x]=len;
a[len][2]=z;
}
void dfs(int t)
{
int i;
for (i=ls[t]; i; i=a[i][1])
if (f[a[i][0]]==-1)
{
f[a[i][0]]=f[t]^a[i][2];
dfs(a[i][0]);
}
else
if (f[a[i][0]]!=(f[t]^a[i][2]))
ans=0;
}
int main()
{
scanf("%d",&T);
for (;T;--T)
{
len=0;
scanf("%d%d%d",&n,&m,&K);
fo(i,1,n+m) f[i]=-1,ls[i]=0;
fo(i,1,K)
{
scanf("%d%d%d%d",&X1,&Y1,&X2,&Y2);
x=min(X1,X2);
y=min(Y1,Y2);
if (x==X1 && y==Y1 || x==X2 && y==Y2) //1
{
New(x,n+y,0);
New(n+y,x,0);
}
else //2
{
New(x,n+y,1);
New(n+y,x,1);
}
}
ans=1;
fo(i,1,n+m)
if (f[i]==-1)
f[i]=0,dfs(i);
if (ans)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}