hdu 3879(最大权闭包)

题目链接:

网上一大牛说的好:结论:正的权值的和-建图后的最小割的容量

 选择了一条边就会选择两个点,边的花费为正,点的花费为负,把边看成点,这个点向两个端点连一条边,表示选择这条边就会选择这两个点

然后题目就相当于最大权闭合图的模型了(最大权闭包模型中vs与正收益的点连边,负收益的点与vt连边,容量取绝对值,然后点与点之间连容量为inf的边)

题意:有n个点,m个选择,建造n个点各自需要一定花费,每个选择有一定的获利,会选择两个点,当然也要花费。求最大的获利

每个选择看成是获利点,每个点看成是花费点,新建源点向获利点建边,权值为获利的大小,花费点向汇点建边,权值为花费的大小

每个选择向相应的两个点连一条容量为无穷大的边,然后求网络的最小割答案就为正的权值和-最小割的容量

最小割肯定为简单割(直接与源点或汇点相连),在这个题目中,如果与汇点相连的边为割边,表示这个点没有被选择来建station

如果与源点相连的边为割边,表示不选择某个客户的要求来连接某两个station

所以可以理解成:最终收益所有可能收益-(损失的收益+架设费用)括号中的即为最小割所求

View Code
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 #define MAXN 55555
 6 #define MAXM 5555555
 7 #define inf 1<<30
 8 struct Edge{
 9     int v,cap,next;
10 }edge[MAXM];
11 
12 int head[MAXN];
13 int pre[MAXN];
14 int cur[MAXN];
15 int level[MAXN];
16 int gap[MAXN];
17 int NE,NV,vs,vt,n,m;
18 
19 void Insert(int u,int v,int cap,int cc=0){
20     edge[NE].v=v;edge[NE].cap=cap;
21     edge[NE].next=head[u];head[u]=NE++;
22 
23     edge[NE].v=u;edge[NE].cap=cc;
24     edge[NE].next=head[v];head[v]=NE++;
25 }
26 
27 int SAP(int vs,int vt){
28     memset(pre,-1,sizeof(pre));
29     memset(level,0,sizeof(level));
30     memset(gap,0,sizeof(gap));
31     for(int i=0;i<=NV;i++)cur[i]=head[i];
32     int u=pre[vs]=vs,maxflow=0,aug=-1;
33     gap[0]=NV;
34     while(level[vs]<NV){
35 loop:
36         for(int &i=cur[u];i!=-1;i=edge[i].next){
37             int v=edge[i].v;
38             if(edge[i].cap&&level[u]==level[v]+1){
39                 aug==-1?aug=edge[i].cap:aug=min(aug,edge[i].cap);
40                 pre[v]=u;
41                 u=v;
42                 if(v==vt){
43                     maxflow+=aug;
44                     for(u=pre[u];v!=vs;v=u,u=pre[u]){
45                         edge[cur[u]].cap-=aug;
46                         edge[cur[u]^1].cap+=aug;
47                     }
48                     aug=-1;
49                 }
50                 goto loop;
51             }
52         }
53         int minlevel=NV;
54         for(int i=head[u];i!=-1;i=edge[i].next){
55             int v=edge[i].v;
56             if(edge[i].cap&&minlevel>level[v]){
57                 cur[u]=i;
58                 minlevel=level[v];
59             }
60         }
61         if(--gap[level[u]]==0)break;
62         level[u]=minlevel+1;
63         gap[level[u]]++;
64         u=pre[u];
65     }
66     return maxflow;
67 }
68 
69 int main(){
70     while(~scanf("%d%d",&n,&m)){
71         vs=0,vt=n+m+1,NV=n+m+2,NE=0;
72         memset(head,-1,sizeof(head));
73         int u,v,w,sum=0;
74         for(int i=1;i<=n;i++){
75             scanf("%d",&w);
76             Insert(i,vt,w);
77         }
78         for(int i=1;i<=m;i++){
79             scanf("%d%d%d",&u,&v,&w);
80             sum+=w;
81             Insert(vs,i+n,w);//边看成点
82             Insert(i+n,u,inf);
83             Insert(i+n,v,inf);
84         }
85         printf("%d\n",sum-SAP(vs,vt));
86     }
87     return 0;
88 }

 

posted @ 2013-05-10 21:21  ihge2k  阅读(476)  评论(0编辑  收藏  举报