标签:
Time Limit: 2000MS | Memory Limit: 65536K | |||
Total Submissions: 8158 | Accepted: 2620 | Special Judge |
Description
Input
Output
Sample Input
3 6 1 2 3 4 2 1 1 2 1 1 3 2 1 2 3 1 2 3
Sample Output
5 3 1 + 2 - 2 +
【分析】首先得拆点,一个点拆成in和out。很明显就是求最小点权覆盖集。最小点权覆盖集的求解可以借鉴二分图匹配的最大流解法。
再加上额外的源点S和汇点T后,将匹配以一条s-u-v-t形式的流路径串联起来。匹配的限制在顶点上,恰当的利用了流的容量限制。
而点覆盖集的限制在边上,最小割是最大流的对偶问题,对偶往往是将问题的性质从顶点转边,从边转顶点。可以尝试转最小割模型。
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> #include <string> #include <map> #include <queue> #include <vector> #define inf 0x7fffffff #define met(a,b) memset(a,b,sizeof a) typedef long long ll; using namespace std; const int N = 205; const int M = 11005; int read() {int x=0,f=1;char c=getchar();while(c<‘0‘||c>‘9‘) {if(c==‘-‘)f=-1;c=getchar();}while(c>=‘0‘&&c<=‘9‘) {x=x*10+c-‘0‘;c=getchar();}return x*f;} int n,m,cnt; int win[N],wout[N]; bool flag; int toto=0; struct Dinic { int s,t; struct Edge { int nxt,to,cap,flow; } edg[M]; bool vv[N]; bool vis[N]; int d[N]; int h[N]; int cur[N]; void init() { met(h,-1); } void AddEdge(int x,int y,int z) { edg[toto].to=y; edg[toto].nxt=h[x]; edg[toto].cap=z; h[x]=toto++; edg[toto].to=x; edg[toto].nxt=h[y]; h[y]=toto++; } bool BFS() { memset(vis,0,sizeof(vis)); queue<int>q; q.push(s); d[s]=0; vis[s]=1; while (!q.empty()) { int x = q.front(); q.pop(); for (int i = h[x]; i!=-1; i=edg[i].nxt) { int v=edg[i].to; if (!vis[v] && edg[i].cap > edg[i].flow) { vis[v]=1; d[v] = d[x]+1; q.push(v); if(flag)vv[v]=true; } } } return vis[t]; } int DFS(int x,int a) { if (x==t || a==0) return a; int flow = 0,f; for(int &i=cur[x]; i!=-1; i=edg[i].nxt) { int v=edg[i].to; if (d[x]+1 == d[v] && (f=DFS(v,min(a,edg[i].cap-edg[i].flow)))>0) { edg[i].flow+=f; edg[i^1].flow-=f; flow+=f; a-=f; if (a==0) break; } } return flow; } int Maxflow(int s,int t) { this->s=s; this->t=t; int flow = 0; while (BFS()) { for(int i=0; i<=t; i++)cur[i]=h[i]; flow+=DFS(s,inf); } return flow; } } dc; int main() { while (~scanf("%d%d",&n,&m)) { dc.init(); met(wout,0); met(win,0); flag=false; for(int i=1; i<=n; i++)win[i]=read(); for(int i=1; i<=n; i++)wout[i]=read(); while(m--) { int u=read(); int v=read(); dc.AddEdge(u,v+n,inf); } for(int i=1; i<=n; i++) { dc.AddEdge(0,i,wout[i]); dc.AddEdge(i+n,2*n+1,win[i]); } printf("%d\n",dc.Maxflow(0,2*n+1)); int sum=0; flag=true; dc.BFS(); for(int i=1; i<=n; i++) { if(!dc.vv[i])sum++; if(dc.vv[n+i])sum++; } printf("%d\n",sum); for(int i=1; i<=n; i++) { if(!dc.vv[i])printf("%d -\n",i); if(dc.vv[n+i])printf("%d +\n",i); } } return 0; }
POJ2125 Destroying The Graph (最小点权覆盖集)(网络流最小割)
标签:
原文地址:http://www.cnblogs.com/jianrenfang/p/5933705.html