题目来源:http://www.fjutacm.com/Problem.jsp?pid=3443
思路:建边时将输入的map[a][b]=0,之后先跑一边最大匹配,在找到匹配点对后,一个个匹配点对枚举,如果这个点对的连接边去掉以后再跑一遍二分图最大匹配不变,则说明这对手套不是肯定的一对;如果最大匹配改变了则说明这点对是必选的,则可以将这一对记录在答案里,最后输出;
#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;
}