hdu6598(最小割)

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=6598

题意

给定 $n$ 个点,$m$ 条边,将这 $n$ 个点黑白染色,对每条边,如果两个点同是黑色,产生 $a$ 贡献,同是白色,产生 $b$ 贡献,否则产生 $c$ 贡献,问产生的最大贡献

题解

一个十分神奇的模型。。直接贴题解。。

分成两个点集的问题可以用最小割解决,考虑一条边的情况,可以构造下图

由于要求最大价值,所以用割边代表损失的价值,用总价值减去最小割即可。。那么有

解得

然后对所有边进行一次累加,图就建完了。。




代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/**
*         ┏┓    ┏┓
*         ┏┛┗━━━━━━━┛┗━━━┓
*         ┃       ┃  
*         ┃   ━    ┃
*         ┃ >   < ┃
*         ┃       ┃
*         ┃... ⌒ ...  ┃
*         ┃ ┃
*         ┗━┓ ┏━┛
*          ┃ ┃ Code is far away from bug with the animal protecting          
*          ┃ ┃ 神兽保佑,代码无bug
*          ┃ ┃           
*          ┃ ┃       
*          ┃ ┃
*          ┃ ┃           
*          ┃ ┗━━━┓
*          ┃ ┣┓
*          ┃ ┏┛
*          ┗┓┓┏━━━━━━━━┳┓┏┛
*           ┃┫┫ ┃┫┫
*           ┗┻┛ ┗┻┛
*/

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<set>
#include<bitset>
#include<complex>
#include<assert.h>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y)/2
#define NM 505
#define nm 30005
using namespace std;
const double pi=acos(-1);
const ll inf=1e18;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}




struct edge{int t;ll v;edge*next,*rev;}e[nm],*h[NM],*o=e,*tmp[NM],*p[NM];
void _add(int x,int y,int v){o->t=y;o->v=v;o->next=h[x];h[x]=o++;}
void add(int x,int y,int v){_add(x,y,v);_add(y,x,0);h[x]->rev=h[y];h[y]->rev=h[x];}

int n,m,_a,_b,_c,_x,_y;
int tot,cnt[NM],d[NM];
ll a[NM],b[NM],s;

ll maxflow(){
ll flow=0;edge*j;
inc(i,0,n)tmp[i]=h[i],cnt[i]=d[i]=0;
cnt[0]=tot=n+1;
ll s=inf;
for(int x=0;d[x]<tot;){
for(j=tmp[x];j;j=j->next)if(j->v&&d[j->t]+1==d[x])break;
if(j){
s=min(s,j->v);tmp[x]=p[j->t]=j;
if((x=j->t)==n){
for(;x;x=p[x]->rev->t)p[x]->v-=s,p[x]->rev->v+=s;
flow+=s;s=inf;
}
}else{
if(!--cnt[d[x]])break;d[x]=tot;
link(x)if(j->v&&d[x]>d[j->t]+1)d[x]=d[j->t]+1,tmp[x]=j;
cnt[d[x]]++;
if(p[x])x=p[x]->rev->t;
}
}
return flow;
}


int main(){
while(~scanf("%d%d",&n,&m)){
inc(i,1,n)a[i]=b[i]=0;
inc(i,0,n+1)h[i]=0;
o=e;s=0;
while(m--){
_x=read();_y=read();_a=read();_b=read();_c=read();
s+=_a+_b+_c;
a[_x]+=_b+_c;a[_y]+=_b+_c;
b[_x]+=_a+_b;b[_y]+=_a+_b;
_add(_x,_y,_a+_c-2*_b);_add(_y,_x,_a+_c-_b*2);
h[_x]->rev=h[_y];h[_y]->rev=h[_x];
}
inc(i,1,n)add(0,i,a[i]),add(i,n+1,b[i]);
s<<=1;
n++;
printf("%lld\n",s-maxflow()>>1);
}
return 0;
}