Description
给 (n imes n) 的网格图的边染 (k) 种颜色,每种颜色染的边数相同,构造不存在同色环,且没有某一整行或整列的颜色相同的方案数。
Solution
约定左上角的格点为 ((0,0)),由一个点 ((i,j)) 向右发出的边记做 ((i,j,0)),向下发出的边记做 ((i,j,1))。
先考虑两种颜色时怎么放。
若 (n) 为偶数,则选取 (0,0,0),(0,2,0),(0,4,0),...,(1,1,0),(1,3,0),(1,5,0),...,(2,0,0),(2,2,0),(2,4,0),...,...,(0,0,1),(0,1,1),(0,2,1),...,(2,0,1),(2,1,1),(2,2,1),...,...,...
若 (n) 为奇数,则按 ((i,j,k)) 的 ((i+j) mod 2) 定色。
考虑 (k) 种颜色且 (k) 为偶数时,我们将原先的黑色中任意分出若干个给 ([k/2-1]) 种新颜色,将原先的白色中任意分出若干个给另外 ([k/2-1]) 种新颜色。
当 (k) 为奇数时,我们需要分 (siz) 条边给多出来的那一种颜色,我们只需要从左半图中贪心地取若干条黑边,右半图中贪心地取若干白边,数量分别为 (frac {siz} {2}),然后再按 (k) 为偶数的情况继续执行即可。
#include<bits/stdc++.h>
using namespace std;
const int N = 205;
int f[N][N][2];
void solve(int n,int k)
{
// Step 0
for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) f[i][j][0]=f[i][j][1]=0;
for(int i=0;i<=n;i++) f[n][i][1]=f[i][n][0]=-1;
// Step 1
if(n&1)
{
for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) for(int k=0;k<2;k++) if(f[i][j][k]!=-1) f[i][j][k]=(i+j+1)%2;
}
else
{
for(int i=0;i<=n;i++) for(int j=i&1;j<n;j+=2) f[i][j][0]=1;
for(int i=0;i<n;i+=2) for(int j=0;j<=n;j++) f[i][j][1]=1;
}
// Step 2
if(k&1)
{
int c=k-1,tot=2*n*(n+1)/k,cnt=0;
for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) for(int k=1;k>=0;k--) if(f[i][j][k]==0 && cnt<tot/2) f[i][j][k]=c, ++cnt;
for(int i=n;i>=0;i--) for(int j=n;j>=0;j--) for(int k=1;k>=0;k--) if(f[i][j][k]==1 && cnt>0) f[i][j][k]=c, --cnt;
}
// Step 3
if(k>2)
{
int t=(k-2)/2,cnt=0,siz=2*n*(n+1)/k;
for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) for(int k=1;k>=0;k--)
{
int c=2+cnt/siz;
if(c<=2+t-1)
{
if(f[i][j][k]==0) f[i][j][k]=c,++cnt;
}
}
for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) for(int k=1;k>=0;k--)
{
int c=2+cnt/siz;
if(c<=2+2*t-1)
{
if(f[i][j][k]==1) f[i][j][k]=c,++cnt;
}
}
}
// Output
for(int i=0;i<=n;i++)
{
for(int j=0;j<n;j++) printf("%d ",f[i][j][0]+1);
puts("");
}
for(int i=0;i<=n;i++)
{
for(int j=0;j<n;j++) printf("%d ",f[j][i][1]+1);
puts("");
}
}
int T,n,k;
bool TP()
{
if(n==1||k<=1||2*(n+1)*n%k!=0)
{
printf("-1
");
return true;
}
if(n==2&&k==3)
{
printf("1 2
");
printf("3 1
");
printf("3 2
");
printf("1 3
");
printf("2 1
");
printf("2 3
");
return true;
}
if(n==3&&k==3)
{
printf("1 2 3
");
printf("2 3 2
");
printf("1 3 1
");
printf("3 1 2
");
printf("3 2 1
");
printf("3 1 2
");
printf("1 2 3
");
printf("2 1 3
");
return true;
}
return false;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&k);
if(!TP()) solve(n,k);
}
return 0;
}
// Checker
/*map<int,int> mp;
for(int i=0;i<=n;i++) for(int j=0;j<=n;j++)
{
mp[f[i][j][0]]++;
mp[f[i][j][1]]++;
}
int siz=2*n*(n+1)/k;
for(auto i:mp) if(i.first>=0) if(i.second!=siz) cout<<"FAILED A"<<endl;
for(int i=0;i<=n;i++) for(int j=0;j<=n;j++)
{
if(f[i][j][0]==f[i][j+1][0] && j+1<=n) cout<<"FAILED B"<<endl;
if(f[i][j][1]==f[i+1][j][1] && i+1<=n) cout<<"FAILED B"<<endl;
}
for(int i=0;i<n;i++) for(int j=0;j<n;j++)
{
set<int> s;
s.insert(f[i][j][0]);
s.insert(f[i][j][1]);
s.insert(f[i+1][j][0]);
s.insert(f[i][j+1][1]);
if(s.size()==1) cout<<"FAILED C"<<endl;
}*/