看到这种矩阵构造又有奇怪约束的题目,考虑建图解决。
但是 $C<n$ 的情况可能会出现无解。考虑把原矩阵补成一个 $C=n$ 的矩阵(就是把右上角那一块填上)。仍然使用上面的做法,这次由**值**向**行**连边,然后每条边的颜色就是其所在的列。注意如果使用的颜色数 $p$ 与 $n-C$ 不相等,说明无解。
使用找 $\mathrm{mex}$ 然后调整冲突的方法进行二分图边染色,封装成一个类似乎比较好写。代码实现中使用了 C++17 中的 `std::variant`,使用方法见[这里](https://en.cppreference.com/w/cpp/utility/variant)。
放代码:
```cpp
#include<bits/stdc++.h>
#define int short
using namespace std;
class EdgeColoring{
private:
vector<int> d;
vector<vector<int> > a;
// a[i][j] 表示 i 结点出发的颜色为 j 的边到达哪个点
public:
EdgeColoring(int n,int m){
d.resize(n+m);
a.resize(n+m,vector<int>(n+m,-1));
} // 初始化
int add_edge(int u,int v){
d[u]++,d[v]++; // 记录度数,判断无解用
int c1=0,c2=0;
while(~a[u][c1])c1++;
while(~a[v][c2])c2++; // 找 mex
a[u][c1]=v,a[v][c2]=u;
if(c1!=c2) // 有冲突
for(int c3=c2,i=v;~i;i=a[i][c3],c3^=c1^c2)
swap(a[i][c1],a[i][c2]); // 调整
return c1;
}
pair<int,vector<vector<int> > > color(){
return make_pair(*max_element(d.begin(),d.end()),a);
} // 返回值前者为颜色数,后者为染色方案
}; // 二分图边染色
variant<vector<vector<int> >,bool> f1(int n,vector<vector<int> > &a){
vector s(a.size(),vector<int>(n));
for(int i=0;i<a.size();i++)
for(int j=0;j<a[0].size();j++)
s[i][j]=a[i][j];
EdgeColoring g(n,a.size());
for(int i=0;i<a.size();i++){
vector<bool> b(n);
for(int j=0;j<a[0].size();j++)
b[a[i][j]-1]=true;
for(int j=0;j<n;j++)
if(!b[j])g.add_edge(j,i+n);
} // 建图
auto [p,m]=g.color(); // 染色
if(p!=n-a[0].size())return false; // 无解
for(int i=0;i<n;i++)
for(int j=0;j<n-a[0].size();j++)
if(~m[i][j])s[m[i][j]-n][j+a[0].size()]=i+1; // 构造
return s;
}
vector<vector<int> > f2(int n,vector<vector<int> > &a){
vector s(n,vector<int>(n));
for(int i=0;i<a.size();i++)
s[i]=a[i];
EdgeColoring g(n,n);
for(int i=0;i<n;i++){
vector<bool> b(n);
for(int j=0;j<a.size();j++)
b[a[j][i]-1]=true;
for(int j=0;j<n;j++)
if(!b[j])g.add_edge(j,i+n);
}
auto m=g.color().second;
for(int i=0;i<n;i++)
for(int j=0;j<n-a.size();j++)
if(~m[i][j])s[j+a.size()][m[i][j]-n]=i+1;
return s;
}
main(){
ios::sync_with_stdio(false);
int t; cin>>t;
while(t--){
int n,r,c; cin>>n>>r>>c;
vector a(r,vector<int>(c));
for(auto &i:a)for(auto &j:i)cin>>j;
if(auto s=f1(n,a);get_if<bool>(&s))cout<<"No\n";
else{
auto s2=f2(n,get<vector<vector<int> > >(s));
cout<<"Yes\n";
for(auto i:s2){
for(int j:i)cout<<j<<' ';
cout<<'\n';
}
}
}
return 0;
}
```