2020牛客暑期多校训练营第六场Grid Coloring

Grid Coloring

原题请看这里

题目描述:

R o u n d g o d Roundgod 绘制了一个包含 n n n*n 格子的图,他可以用 k k 种颜色,对每一条边进行染色,但有一些限制:

  1. 每种颜色必须出现相同次数
  2. 图上不能有单色环
  3. 每一行和每一列,至少包含 2 2 种颜色。

输入描述:

输入包含多个测试用例。 输入的第一行包含一个整数 T T ( ( 1 1 \le T T \le 100 100 ) ) 在接下来的 T T 行中,每行包含两个整数 n n k k ( ( 1 1 \le n n \le 200 200 , 1 1 \le k k \le 2 ( n + 1 ) n ) 2(n+1)n) ,描述一个测试用例。

输出描述:

对于每个测试用例,如果没有解决方案,请输出 1 -1 。否则,输出 2 ( n + 1 ) 2(n+1) 行。 对于前 n + 1 n+1 行,每行包含 n n 个整数,表示每条水平线上的边缘颜色;对于后 n + 1 n+1 行,每行包含 n n 个整数,表示每条垂直线上的边缘颜色。

样例输入:

2
2 3
2 5

样例输出:

1 2
3 1
3 2
1 3
2 1
2 3
-1

思路:

首先,我们可以排除三种无解的情况: k = 1 n = 1 2 n ( n + 1 ) k=1,n=1,2n(n+1) m o d mod k ! = 0 k!=0
然后我们就按照如下方式对图进行标号:
在这里插入图片描述
所以我们的标号方式是:自顶向下分别给边按照 1 1 n n 的顺序标号(如上图),然后我们将颜色 1 1 k k 按照顺序轮流放到这些边上。
1.对于每一个 1 1 1*1 的小环,两条纵边必定是相邻的序号,所以染的颜色必然不同
2.对于任意一个 a ( a + b ) , b > 0 a(a+b),b>0 的环,横向边必定有相邻序号,所以染的颜色必然不同,由此又可以证明所有的横向边都是异色的
3.对于任意一个 ( a + b ) a , b > 0 (a+b)a,b>0 的环,如果他的横向边长为1,那么他就有相邻的纵向边,如果他的横向边 > 1 >1 那么他就有相邻横向边
所以任意一个环和横边均异色。
然后观察上图,发现:任意两条相邻纵向边的序号差必定为 2 n + 1 2n+1
推理到这一步,我们只要证明任意两条相邻纵向边必定异色即可,即 g c d ( k , 2 n + 1 ) = 1 gcd(k,2n+1)=1 ,也就是 g c d ( 2 n ( n + 1 ) , 2 n + 1 ) = 1 gcd(2n(n+1),2n+1)=1
证明:
g c d ( 2 n ( n + 1 ) , 2 n + 1 ) = 1 gcd(2n(n+1),2n+1)=1
\leftrightarrow g c d ( 2 n ( n + 1 ) n ( 2 n + 1 ) , 2 n + 1 ) = 1 gcd(2n(n+1)-n(2n+1),2n+1)=1
\leftrightarrow g c d ( n , 2 n + 1 n ) = 1 gcd(n,2n+1-n)=1 \leftrightarrow g c d ( n , n + 1 ) = 1 gcd(n,n+1)=1
得证。
我还真不信如此复杂的推理得出的代码竟是如此简便…

A C AC C o d e Code

#include<bits/stdc++.h>
using namespace std;
const int MAXN=205;
int a[MAXN][MAXN],b[MAXN][MAXN],T,n,k,t;
int main(){
    scanf("%d",&T);
    while(T--){
    	t=0;
        scanf("%d%d",&n,&k);
        if(n==1|| k==1||(2*n*(n+1))%k){
            puts("-1");
            continue;
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
				t=t%k+1;
				a[i][j]=t;
			}
            for(int j=0;j<=n;j++){
				t=t%k+1;
				b[j][i]=t;
			}
        }
        for(int i=0;i<n;i++){
			t=t%k+1;
			a[n][i]=t;
		}
        for(int i=0;i<=n;i++){
            for(int j=0;j<n;j++)
                printf("%d ",a[i][j]);
            puts("");
        }
        for(int i=0;i<=n;i++){
            for(int j=0;j<n;j++)
                printf("%d ",b[i][j]);
            puts("");
        }
    }
}

猜你喜欢

转载自blog.csdn.net/s260127ljy/article/details/107637810