二分图最大匹配 输出字典序最小的方案 poj 3715

来源:互联网 发布:centos gcc 编辑:程序博客网 时间:2024/06/06 19:21

http://poj.org/problem?id=3715

暴力也可以水过:先求最大匹配,然后从小到大枚举点去掉,重新求最大匹配,如果最大匹配数减少了,则这个点可以去掉。

比较好的做法应该是充分利用二分匹配匈牙利算法的性质,如果去掉一个点之后从这个点匹配的那个点出发找不到增广路,就可以将这个点删除,这样子做就不用每次都求全局最大匹配了,赞一个。。 

#include<cstdio>#include<cstring>const int M  =  210;bool g[M][M] ,  vis[M] , deleted[M] , grp[M];int px[M] , py[M] ;int n;bool canx(int x){if(deleted[x]) return false;for(int i = 0; i < n; i++){if(!g[x][i] || vis[i]  || deleted[i] || !grp[i]) continue;vis[i] = true;if(py[i]==-1 || canx(py[i])){px[x] = i; py[i] = x;return true;}}return false;}bool cany(int y){if(deleted[y]) return false;for(int i = 0; i < n; i++){if(!g[y][i] || vis[i] || deleted[i] || grp[i]) continue;vis[i] = true;if(px[i]==-1 || cany(px[i])){px[i] = y;py[y] = i;return true;}}return false;}int main(){int t,m,i,j,k;scanf("%d",&t);while(t--){scanf("%d%d",&n,&m);memset(g,false,sizeof(g));memset(deleted,false,sizeof(deleted));memset(px,-1,sizeof(px));memset(py,-1,sizeof(py));for(i = 0; i < n; i++) scanf("%d",&grp[i]);for(i = 0; i < m; i++){scanf("%d%d",&j,&k);if(grp[j] != grp[k]){g[j][k] = g[k][j] = true;}}int ans = 0;for(i = 0; i < n; i++) if(grp[i]==0){memset(vis,false,sizeof(vis));ans += canx(i);}printf("%d",ans);int x,y;for(i = 0; i < n && ans; i++){if(!grp[i]){if(px[i] == -1 ) continue;y = px[i];deleted[i] = true;px[i] = -1;py[y] = -1;memset(vis,false,sizeof(vis));if(cany(y)){deleted[i] = false;}else printf(" %d",i);}else {if(py[i] == -1) continue;x = py[i];deleted[i] = true;py[i] = -1;px[x] = -1;memset(vis,false,sizeof(vis));if(canx(x)){deleted[i] = false;}else printf(" %d",i);}}puts("");}return 0;}


原创粉丝点击