agc037d Sorting a Grid
给出一个 \(n\) 行 \(m\) 列的矩阵,每个格子里面的值分别为 \(a_{i,j}\),保证值不重复。
现在可以进行三波操作。
- 对每一行,随意重排行里面的数。
- 对每一列,随意重排列里面的数。
- 对每一行,随意重排行里面的数。
\(1\leq n,m\leq 100, 1\leq a_{i,j}\leq nm\)
对于在位置 \((i,j)\) 的值,最重要到位置 \((x,y)\) ,这是固定的。观察轨迹,发现移动方式是 \((i,j) \rightarrow (i,k)\rightarrow (x,k)\rightarrow (x,y)\).
可以考虑这样一张图,左边一列点 \(i\),其中 \(1\leq i\leq n\);右边一列点 \(i'\), \(1\leq i'\leq n\).
对于每个 \((i,j)\),找到对应 \((x,y)\) 后, 由 \(i\) 向 \(x'\) 连边(无向)。
这样就发现这是一个 \(m\) 染色的问题,要给边由 \(1\) 到 \(m\) 染色,使得每个点相邻的边颜色都互不相同。
根据 hall 定理可以得到。这样的一个染色问题,每种颜色的边集合是一个完美匹配。
此时就可以通过网络流来解决这个问题了。跑 \(m\) 次网络流,找 \(m\) 次完美匹配。
时间复杂度: 我不会分析
空间复杂度: \(O(nm)\)
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
const int N=1e4+5;
const int inf=1e9;
struct edge{int to,cap,rev,id;};
vector<edge>g[N];int itr[N];
inline void ae(int u,int v,int w,int id){
g[u].pb((edge){v,w,(int)g[v].size(),id});
g[v].pb((edge){u,0,(int)g[u].size()-1,-1});
}
queue<int>q;int lv[N];
bool bfs(int s,int t){
memset(lv,-1,sizeof(lv));
lv[s]=0;q.push(s);
while(!q.empty()){
int x=q.front();q.pop();
for(auto e:g[x]){
int to=e.to,cap=e.cap;
if(lv[to]==-1&&cap){
lv[to]=lv[x]+1;
q.push(to);
}
}
}
// for(int i=1;i<=n;i++)cerr<<lv[i]<<" ";cerr<<endl;
return lv[t]!=-1;
}
int dfs(int x,int t,int flow){
// cerr<<x<<" "<<t<<" "<<flow<<endl;
if(x==t)return flow;
for(int&i=itr[x];i<(int)g[x].size();i++){
edge&e=g[x][i];
if(lv[e.to]>lv[x]&&e.cap){
int d=dfs(e.to,t,min(e.cap,flow));
if(d){
e.cap-=d;
g[e.to][e.rev].cap+=d;
return d;
}
}
}
return 0;
}
int get_flow(int s,int t){
int res=0;
while(bfs(s,t)){
memset(itr,0,sizeof(itr));
int d;
while(d=dfs(s,t,inf))res+=d;
res+=d;
}
return res;
}
int n,m;
int a[105][105],b[105][105],c[105][105];
signed main(){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)for(int j=0;j<m;j++)scanf("%d",&a[i][j]);
for(int i=0;i<n;i++)for(int j=0;j<m;j++)a[i][j]--;
for(int i=0;i<n;i++)for(int j=0;j<m;j++){
int x=a[i][j]/m,y=a[i][j]%m;
ae(i,x+n,1,i*m+j);
}
for(int i=0;i<n;i++){
ae(2*n,i,1,-1);
ae(i+n,2*n+1,1,-1);
}
for(int t=0;t<m;t++){
int res=get_flow(2*n,2*n+1);
assert(res==n);
// cerr<<"t="<<t+1<<endl;
for(int i=0;i<n;i++)for(auto&e:g[i]){
int to=e.to,cap=e.cap,rev=e.rev,id=e.id;
if(n<=to&&to<2*n&&cap==0&&id!=-1){
int j=id%m,x=a[i][j]/m,y=a[i][j]%m;
// cerr<<i+1<<" "<<j+1<<"\n";
b[i][t]=a[i][j];
c[x][t]=a[i][j];
g[to][rev].cap=0;
e.id=-1;
}
}
for(auto&e:g[2*n]){
int to=e.to,cap=e.cap,rev=e.rev;
if(to<n&&cap==0){
e.cap=1;
g[to][rev].cap=0;
}
}
for(auto&e:g[2*n+1]){
int to=e.to,cap=e.cap,rev=e.rev;
if(n<=to&&to<2*n&&cap==1){
e.cap=0;
g[to][rev].cap=1;
}
}
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++)printf("%d ",b[i][j]+1);
printf("\n");
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++)printf("%d ",c[i][j]+1);
printf("\n");
}
return 0;
}
写完才发现我 5 年前做过这个题目,真是震惊了。

浙公网安备 33010602011771号