垃圾佬的手套 二分图匹配
题目来源: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\n", i, ans[i]); } } return 0; }