专栏文章

题解:AT_abc317_g [ABC317G] Rearranging

AT_abc317_g题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@mioyggfh
此快照首次捕获于
2025/12/03 03:12
3 个月前
此快照最后确认于
2025/12/03 03:12
3 个月前
查看原文
前置芝士:二分图最大匹配

正文开始

阅读理解:

有一个 NNMM 列的图,其中有数值为 1N1∼N 的数各 MM 个。你可以对每一行进行任意排列,能否在每一列中数值为 1N1∼N 的数各出现一次?输出方案。

思路:

可以发现,这道题是必定能完成目标的,因为当有 MM 列时,你一定可以凑出一列数值为 1N1∼N 的数各出现一次,删掉这一列后,剩余的矩阵依旧满足题目所述条件,所以可以重复上面操作,以此类推。
方案如何处理呢?我们可以每次处理当前的首列,将这一列的每一排当作二分图的左边一部分,然后将每一排剩下还可以选的数字与其对应的排相连,然后跑一个二分图最大匹配即可,最后统计答案。

代码

CPP
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e2+5;
int n,m,e;
int a[N][N],v[N][N];
int b[N],li[N],ans[N][N];
inline bool find(int u){
	for(int i=1;i<=n;i++)
		if(v[u][i]>0&&!b[i]){
			b[i]=1;
			if(!li[i]||find(li[i])){li[i]=u;return 1;}
		}
	return 0;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)cin>>a[i][j],v[i][a[i][j]]++;
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){memset(b,0,sizeof(b)),find(j);}//跑二分图最大匹配 
		for(int j=1;j<=n;j++)ans[li[j]][i]=j,v[li[j]][j]--,li[j]=0;//统计答案 
	}
	cout<<"Yes\n";
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++)cout<<ans[i][j]<<' ';
		cout<<'\n';
	}
	return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...