POJ 2125 最小割

题意:

N个点M条边的有向图,给出如下两种操作。
删除点i的所有出边,代价是Ai。
删除点j的所有入边,代价是Bj。
求最后删除图中所有的边的最小代价。

其实就是二分图最小点权覆盖。

定义:从x或者y集合中选取一些点,使这些点覆盖所有的边,并且选出来的点的权值尽可能小。

题解:

拆点。n个点拆成2n个点(左右各n个,i与(i+n)对应,之间连容量INF的边),S和i连容量为Ai的边,(i+n)与T之间连容量为Bi的边,求最小割即可

这样做为什么对呢?

当一条边存在的条件就是网络中还存在从S到T的非满流边!

方案输出不多说。。

 

View Code
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <iostream>
 5 
 6 #define N 300
 7 #define M 20000
 8 #define INF 99999999
 9 
10 using namespace std;
11 
12 int to[M],next[M],head[N],len[M],cnt,layer[N],n,m,S,T,q[M];
13 bool vis[N];
14 
15 inline void add(int u,int v,int w)
16 {
17     to[cnt]=v; len[cnt]=w; next[cnt]=head[u]; head[u]=cnt++;
18     to[cnt]=u; len[cnt]=0; next[cnt]=head[v]; head[v]=cnt++;
19 }
20 
21 void read()
22 {
23     memset(head,-1,sizeof head);cnt=0;
24     scanf("%d%d",&n,&m);
25     S=0,T=n+n+1;
26     for(int i=1,a;i<=n;i++) scanf("%d",&a),add(i+n,T,a);
27     for(int i=1,a;i<=n;i++) scanf("%d",&a),add(S,i,a);
28     for(int i=1,a,b;i<=m;i++) scanf("%d%d",&a,&b),add(a,b+n,INF);
29 }
30 
31 bool bfs()
32 {
33     memset(layer,-1,sizeof layer);
34     int h=1,t=2,sta;
35     q[1]=S; layer[S]=0;
36     while(h<t)
37     {
38         sta=q[h++];
39         for(int i=head[sta];~i;i=next[i])
40             if(len[i]>0&&layer[to[i]]<0)
41             {
42                 layer[to[i]]=layer[sta]+1;
43                 q[t++]=to[i];
44             }
45     }
46     return layer[T]!=-1;
47 }
48 
49 int find(int u,int cur_flow)
50 {
51     if(u==T) return cur_flow;
52     int result=0,tmp;
53     for(int i=head[u];~i;i=next[i])
54         if(len[i]>0&&layer[to[i]]==layer[u]+1)
55         {
56             tmp=find(to[i],min(cur_flow-result,len[i]));
57             len[i]-=tmp; len[i^1]+=tmp; result+=tmp;
58         }
59     if(!result) layer[u]=-1;
60     return result;
61 }
62 
63 void dfs(int u)
64 {
65     vis[u]=true;
66     for(int i=head[u];~i;i=next[i])
67         if(!vis[to[i]]&&len[i])
68             dfs(to[i]);
69 }
70 
71 void dinic()
72 {
73     int ans=0;
74     while(bfs()) ans+=find(S,INF);
75     printf("%d\n",ans);
76     dfs(S);
77     ans=0;
78     for(int i=1;i<=n;i++)  
79         ans+=(!vis[i])+(vis[i+n]);  
80        printf("%d\n",ans);
81     for(int i=1;i<=n;i++)  
82     {  
83         if(!vis[i]) printf("%d -\n",i);
84         if(vis[i+n]) printf("%d +\n",i);
85     }
86 }
87 
88 int main()
89 {
90     read();
91     dinic();
92     return 0;
93 }

 

 

posted @ 2013-01-08 22:09  proverbs  阅读(261)  评论(0编辑  收藏  举报