给定N * M的二分图,求最小的边数使得每个点都被至少覆盖2次。
有下界的最小流问题。
先把需要满足的下界跑满(即减去容量)然后再跑不需要的边的最大流。
dinic


#include<stdio.h> #include<string.h> #include<math.h> #include<algorithm> #include<vector> #define LL int using namespace std; const int maxn = 1011; const int maxm = 191010; const LL inf = 10000000; struct Dinic{ int node, src, dest, ne; int head[maxn], work[maxn], dist[maxn],Q[maxn]; LL flow[maxm]; int pnt[maxm], nxt[maxm]; void init(int _node, int _src, int _dest) { node = _node; src = _src; dest = _dest; memset(head, -1 ,sizeof(head)); ne = 0; } void add(int u,int v, LL c1,LL c2) { pnt[ne] = v, flow[ne] = c1, nxt[ne] = head[u], head[u] = ne++; pnt[ne] = u, flow[ne] = c2, nxt[ne] = head[v], head[v] = ne++; } bool dinic_bfs(void) { int i,u,v,l,r=0; for(int i=0;i<node;i++) dist[i]=-1; dist[Q[r++]=src]=0; for(l=0;l<r;l++) for(i=head[u=Q[l]];i>=0;i=nxt[i]) if(flow[i] && dist[v=pnt[i]]<0) { dist[Q[r++]=v]=dist[u]+1; if(v==dest) return 1; } return 0; } LL dinic_dfs(int u,LL exp) { if(u==dest) return exp; LL tmp; for(int &i=work[u],v;i>=0;i=nxt[i]) if(flow[i] && dist[v=pnt[i]]==dist[u]+1 && (tmp=dinic_dfs(v,min(exp,flow[i])))>0) { flow[i]-=tmp; flow[i^1]+=tmp; return tmp; } return 0; } LL dinic_flow(void) { int i; LL res=0,delta; while(dinic_bfs()) { for(i=0;i<node;i++) work[i]=head[i]; while(delta=dinic_dfs(src,inf)) res+=delta; } return res; } }Flow; int n, m, q; int deg[606]; int main() { while (scanf("%d%d%d",&n,&m,&q)==3) { Flow.init(n + m + 2, 0, n + m + 1); memset(deg, 0, sizeof(deg)); for (int i = 1;i<=q;i++) { int u, v; scanf("%d%d",&u,&v); Flow.add(u, n + v, 1 ,0); deg[u]++; deg[v+ n]++; } int flag = 1; for (int i=1;i<=n + m;i++) if (deg[i] < 2){ flag = 0; break; } if (flag == 0) { printf("-1\n\n"); }else{ for (int i=1;i<=n;i++) Flow.add(0, i, deg[i] - 2, 0); for (int j = 1;j<=m;j++) Flow.add(n + j, n + m + 1, deg[n + j] - 2, 0); int ret = Flow.dinic_flow(); printf("%d\n",q - ret); vector<int>ans; ans.clear(); for (int i=1;i<=q;i++) { int e = i * 2 - 2; if (Flow.flow[e] == 1){ ans.push_back(i); } } int sz = ans.size(); for (int i=0;i<sz;i++) { if (i == sz - 1)printf("%d\n",ans[i]); else printf("%d ",ans[i]); } } } return 0; }
本文探讨了在N*M的二分图中,求解最小边数使每个顶点至少被两条边覆盖的问题。采用dinic算法实现,首先满足所有顶点的下界条件,再通过最大流算法寻找额外的边,确保每个顶点至少被覆盖两次。
2237

被折叠的 条评论
为什么被折叠?



