HDU [P2819] swap

二分图行列匹配+输出路径

经典题,当且仅当一行匹配一列的时候,符合题意。
本题的难点在于如何输出路径,我们发现这个移动的过程就是将所有匹配选择排序,在选择排序时输出路径即可

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int init(){
	int rv=0,fh=1;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-') fh=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		rv=(rv<<1)+(rv<<3)+c-'0';
		c=getchar();
	}
	return fh*rv;
}
int n,ma[105][105],g[105][105],match[105];
bool f[105];
bool hungarian(int u){
	for(int i=1;i<=g[u][0];i++){
		int v=g[u][i];
		if(!f[v]){
			f[v]=1;
			if(!match[v]||hungarian(match[v])){
				match[v]=u;
				return 1;
			}
		}
	}
	return 0;
}
int main(){
	while(~scanf("%d",&n)){
		memset(ma,0,sizeof(ma));
		memset(match,0,sizeof(match));
		memset(g,0,sizeof(g));
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				ma[i][j]=init();
				if(ma[i][j]) g[i][++g[i][0]]=j;
			}
		}
		int ans=0;
		for(int i=1;i<=n;i++){
			memset(f,0,sizeof(f));
			if(hungarian(i)) ans++;
		}
		if(ans!=n) printf("-1\n");
		else{	
			int cnt=0;
			int p1[105],p2[105];
			memset(p1,0,sizeof(p1));
			memset(p2,0,sizeof(p2));
			for(int i=1;i<=n;i++){
				int k=i;
				for(int j=i;j<=n;j++){
					if(match[j]<match[k]){
						k=j;
					}
				}
				if(k!=i){
					cnt++;
					p1[cnt]=i;p2[cnt]=k;
					swap(match[i],match[k]);
				}
			}
			printf("%d\n",cnt);
			for(int i=1;i<=cnt;i++){
				printf("C %d %d\n",p1[i],p2[i]);
			}
		}
	}
	return 0;
}
posted @ 2018-01-15 11:02  Mr_Wolfram  阅读(132)  评论(0编辑  收藏  举报