Horizontal-Vertical Permutation 构造、完全图着色
题意
\(n\times n\) 的矩阵,要求 \(\forall k \in[1,n]\) ,第 \(k\) 行和第 \(k\) 列加起来是 \(1...2n-1\)
求出一种可行方案,或输出无解。
题解
(大多是抄的PPT,存个档)
考虑每个位置对哪些目标产生贡献,对角线上的贡献一次,其他的贡献两次。
若 \(n\) 为奇数,\(2n - 1\) 个数都要贡献奇数次,说明每个数都需要有一个在对角线上,但对角线上只有 \(n\) 个位置,要求 \(2n-1\le n\),所以除了 \(n = 1\) 都必然无解。
\(n\) 为奇数时,考虑把所有的 \(2n-1\) 放在对角线上,剩下的位置对于两个目标点连边,构成了一张完全图(有向图)。
对于完全图的所有边,每个边着一种颜色,共有 \(2n-2\) 种颜色,完全图共有 \(n\) 个点。要求每个点相连的任意两条边颜色不同。
所有的\((i,j)\) 和 \((j,i)\) 很烦 \((i<j)\) ,反正他们永远都一起出现,干脆将他们合为一条边,让\((j,i)=(i,j)+n-1\),变成无向完全图,有 \(n-1\) 种颜色,\(n\) 个点。
循环赛:两两之间都打两场。
转化为偶数大小的循环赛划分(这个不太懂啥意思,大致就是上面说的要求的东西...好像网上也没有看到这样叫的)
代码
好难写,,
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mkp make_pair
#define pb push_back
#define PII pair<int, int>
#define PLL pair<ll, ll>
int n, ans[510][510];
int change(int x){
x--; if(x == 0) x = n;
return x;
}
int change2(int x){
x++; if(x == n + 1) x = 1;
return x;
}
int main(){
//用n-1种颜色对n个点的完全图进行着色
scanf("%d", &n);
if(n == 1){
puts("Yes\n1"); return 0;
}
if(n % 2){
puts("No"); return 0;
}
puts("Yes");
for(int i = 2; i <= n; i++){
//标杆指向(1, i),颜色为i-1
// cout<<"calc: "<<i<<endl;
ans[1][i] = ans[i][1] = i - 1;
int qwq = i * 2;
for(int j = 1, k = i, l = i; j <= n / 2 - 1; j++){
k = change(k); if(k == 1 || k == i) k = change(k); if(k == 1 || k == i) k = change(k);
l = change2(l); if(l == 1 || l == i) l = change2(l); if(l == 1 || l == i) l = change2(l);
// cout<<k<<" "<<l<<endl;
ans[k][l] = ans[l][k] = i - 1;
}
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++){
if(i > j) ans[i][j] += n - 1;
if(i == j) ans[i][j] = 2 * n - 1;
printf("%d%c", ans[i][j], (j < n) ? ' ' : '\n');
}
return 0;
}
QwQwQ