Problem Description
垃圾佬有n副手套。
不幸的是,垃圾佬把它们都弄乱了。幸运的是,垃圾佬现在有一些关于手套的信息,他希望从中尽可能多地推测出正确的手套配对信息。
假设n只左手的手套,编号为1,2,3...,n,且n只右手的手套也依次为1,2,3,...,n。
从垃圾佬现在的信息中,可以知道,第i只左手手套肯定不是跟第j只右手手套配对。
请帮助垃圾佬尽可能多地推测出正确的手套配对方案。
Input
输入第一行有两个整数n,m,表示垃圾佬有n副手套以及m对信息。
接来下的m行中,每行有两个数a和b,表示左手手套a肯定不是跟右手手套b配对。
数据保证合法。即不会出现有一只手套跟所有的手套都不配对的情况。
1<=n<=100
0<=m<=n*(n-1)/2
Output
输出有若干行。
每行两个整数a,b,表示左手手套a一定是跟右手手套b配对的。
请按左手手套的编号a从小到大输出。
若不能推测出任意一条正确的配对信息,则输出一行"sorry",不包含引号。
SampleInput
3 3 1 3 2 1 1 2
SampleOutput
1 1
题意:题意也有点不明了,他的意思其实是说,本来所有的手套都可以互相配对的,然后他给出m组不能配对的关系,
然后问你在保证最大配对的情况下,哪些是必须要这样配对的
思路:既然说了要求最大配对,那我们就可以想到二分图,然后问题是哪些是必须要这样配对的,
我们先求出最大匹配,然后就可以枚举每一条配对的边,看一下删掉之后再求最大
匹配时是多少,如果最大匹配依然相同,说明当前这条边可有可无,如果最大匹配不同了,
说明当前这条边已经影响到了最大匹配,是必要的,我们就记录下来
这里我们用到了有点类似于求割点的方法,枚举求哪些是必要的
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; const int N=110; bool vis[N], mat[N][N]; int n, k; int dfs(int i, int *pa){ for(register int j=1; j<=n; ++j){ if(mat[i][j]&&!vis[j]){ vis[j]=1; if(pa[j]==-1||dfs(pa[j], pa)){ pa[j]=i; return 1; } } } return 0; } int ans[N]={}; void work(int &Ans, int *pa){ Ans=0; for(register int i=1; i<=n; ++i) pa[i]=-1; for(register int i=1; i<=n; ++i){ memset(vis, 0, sizeof(vis)); Ans+=dfs(i, pa); } } int main(){ int pa2[N], pa1[N]; int x, y, Ans, tmp; register int i, j, top=0; scanf("%d%d", &n, &k); for(i=1; i<=n; ++i) for(j=1; j<=n; ++j) mat[i][j]=1; for(i=1; i<=k; ++i){ scanf("%d%d",&x,&y); mat[x][y]=0; } work(tmp, pa2); for(i=1; i<=n; ++i){//只枚举了最大匹配的那些边,优化了时间复杂度 if(pa2[i]!=-1){ mat[pa2[i]][i]=0; work(Ans, pa1); if(Ans!=tmp){ ans[pa2[i]]=i; top++; } mat[pa2[i]][i]=1; } } if(!top){ puts("sorry"); return 0; } for(i=1; i<=n; ++i){ if(ans[i]){ printf("%d %d ", i, ans[i]); } } return 0; }