Grid Coloring
2
2 3
2 5
1 2
3 1
3 2
1 3
2 1
2 3
-1
给出一个 n ∗ n n*n n∗n的正方形网格,有 k k k种颜色。现要求你将网格的每一条边染色,使得满足以下3个条件。
l i m i t 1 limit1\qquad limit1所有的颜色的边的数量都是相等的
l i m i t 2 limit2\qquad limit2没有一个环是只有一种颜色的。
l i m i t 3 limit3\qquad limit3没有一条竖直或水平的线是只有一种颜色的。
首先当 n = 1 n=1 n=1时,竖直和水平线总是只有1种颜色的,违反 l i m i t 3 limit3 limit3。当 k = 1 k=1 k=1时,只能染一种颜色,违反 l i m i t 2 , 3 limit2,3 limit2,3。当 总边数 m o d k ≠ 0 \,mod\,k\not=0 modk=0时显然无法满足 l i m i t 1 limit1 limit1,因此也是无解的。
这里先给出构造方法,再证明。
如图,按照图中 1 , 2 , … 1,2,\dots 1,2,…的顺序进行染色,依次染 1 , 2 , 3 , … , k , 1 , 2 , 3 , … 1,2,3,\dots,k,1,2,3,\dots 1,2,3,…,k,1,2,3,…。
证明:
对于 l i m i t 1 limit1 limit1,显然顺序染色一定保证每个颜色相同次数。
对于 l i m i t 2 limit2 limit2,如果环是 1 ∗ 1 1*1 1∗1的,那么纵向的边是编号相邻的,颜色必不同。
\qquad\qquad\,\,\,\,\,\,\,\, 如果环是 A ∗ B A*B A∗B的,那么大于1的那条边有相邻的横边或者有相邻的两条纵边,颜色也不会相同。(纵边只要用n,i,j表示出来modk就可以看出来了,后文会加以证明)
对于 l i m i t 3 limit3 limit3,从上一条可以得出,横的边一定是不同色的,满足,接下来证明纵边。
经过推导发现,纵边用 n n n表示后,相邻的两边的差是 ( 2 n − 1 ) (2n-1) (2n−1),因此,我们只要证明 g c d ( 2 n − 1 , k ) = 1 gcd(2n-1,k)=1 gcd(2n−1,k)=1就可以了。由于总边数是 2 n ( n + 1 ) 2n(n+1) 2n(n+1),所以 k ∣ 2 n ( n + 1 ) k|2n(n+1) k∣2n(n+1)。因此可以证明 gcd ( 2 n − 1 , 2 n ( n + 1 ) ) = 1 \gcd(2n-1,2n(n+1))=1 gcd(2n−1,2n(n+1))=1
gcd ( 2 n ( n + 1 ) , 2 n + 1 ) \,\,\,\,\,\,\gcd(2n(n+1),2n+1) gcd(2n(n+1),2n+1)
= gcd ( 2 n + 1 , 2 n ( n + 1 ) − n ( 2 n + 1 ) ) =\gcd(2n+1,2n(n+1)-n(2n+1)) =gcd(2n+1,2n(n+1)−n(2n+1))
= gcd ( 2 n + 1 , n ) =\gcd(2n+1,n) =gcd(2n+1,n)
= gcd ( n , 2 n + 1 − n ) =\gcd(n,2n+1-n) =gcd(n,2n+1−n)
= gcd ( n , n + 1 ) =\gcd(n,n+1) =gcd(n,n+1)
(用辗转相除法得)
因此相邻的纵向的边是不同色的。
所以上述策略是可行的。
#include
#define ll long long
using namespace std;
const int MAXN=210;
int a[MAXN][MAXN],b[MAXN][MAXN];
int main()
{
int t,n,k;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&k);
if(n==1||k==1||2*n*(n+1)%k){puts("-1");continue;}
int cnt=0;//第cnt条边的色是(cnt-1)%k+1
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cnt=cnt%k+1;
a[i][j]=cnt;
}
for(int j=1;j<=n+1;j++){
cnt=cnt%k+1;
b[j][i]=cnt;
}
}
for(int i=1;i<=n;i++){
cnt=cnt%k+1;
a[n+1][i]=cnt;
}
for(int i=1;i<=n+1;i++){
for(int j=1;j<=n;j++){
printf("%d ",a[i][j]);
}puts("");
}
for(int i=1;i<=n+1;i++){
for(int j=1;j<=n;j++){
printf("%d ",b[i][j]);
}puts("");
}
}
}
难的构造题,灰常难的构造题。