为了博多

P2414 - 为了博多

Description

做了个噩梦,梦见我的 n 把刀到60级会二次变身,变成一个 对推6图有xi点贡献,刷大阪城有yi点贡献 的刀,于是要把刀分成两队一队刷大阪城另一队推6图 。
但是有m对兄弟刀在同一队会有特殊的buff加成,加成值为wi,问怎样分队收益最大,最大值是多少。

Input

第一行两个整数n(刀的数目)(0<=n<=20000),m(兄弟刀的对数)(0<=m<=200000)
接下来n行,每行两个整数xi,yi,分别表示第i把刀对推6图的贡献xi和对刷大阪城的贡献yi。
接下来m行,每行三个整数u,v,wi,分别表示第u把刀和第v把刀是兄弟刀,在一队能产生wi的buff值。

Output

一行一个数字,表示最大收益

Sample Input

3 1
1 10
2 10
10 3
2 3 1000

Sample Output

1023

 

 

A作为源点,B作为汇点。
每把刀与A连一条,B连一条。
兄弟刀直接连一条。
然后跑最大流,总权值-最小割就是答案。
其实这个问题的模型就是二分图点权最大独立集(其实并没有二分图)。
因为对于每一把刀,只能放到A或B,每一对兄弟刀,要么都放到A,要么都放到B,要么不组合在一起,所以求出最小割就可以了。

 1 #include<set>
 2 #include<map>
 3 #include<queue>
 4 #include<stack>
 5 #include<ctime>
 6 #include<cmath>
 7 #include<string>
 8 #include<vector>
 9 #include<cstdio>
10 #include<cstdlib>
11 #include<cstring>
12 #include<iostream>
13 #include<algorithm>
14 #define maxn 20010
15 #define maxm 200010
16 #define inf 199999999999
17 #define LL long long
18 using namespace std;
19 struct data{
20   int nex,to;
21   LL w;
22 }e[maxn*6+maxm*4];
23 int head[maxn*2+maxm*2],edge=-1,lev[maxn*2+maxm*2];
24 void add(int from,int to,LL w){
25   e[++edge].nex=head[from];
26   e[edge].to=to;
27   e[edge].w=w;
28   head[from]=edge;
29 }
30 inline bool bfs(int s,int t){
31   queue<int>q;
32   q.push(s);
33   memset(lev,0,sizeof(lev));
34   lev[s]=1;
35   while(!q.empty()){
36     int u=q.front();
37     q.pop();
38     for(int i=head[u];i!=-1;i=e[i].nex)
39       if(e[i].w>0 && !lev[e[i].to]){
40     lev[e[i].to]=lev[u]+1;
41     q.push(e[i].to);
42     if(e[i].to==t)return 1;
43       }
44   }
45   return 0;
46 }
47 LL dfs(int s,int t,LL k){
48   if(s==t) return k;
49   LL tag=0;
50   for(int i=head[s];i!=-1;i=e[i].nex)
51     if(e[i].w>0 && lev[e[i].to]==lev[s]+1){
52       int d=dfs(e[i].to,t,min(k-tag,e[i].w));
53       e[i].w-=d;
54       e[i^1].w+=d;
55       tag+=d;
56       if(tag==k) return tag;
57     }
58   return tag;
59 }         
60 LL dinic(int s,int t){
61   LL flow=0;
62   while(bfs(s,t)) flow+=dfs(s,t,inf);
63   return flow;
64 }
65 int main()
66 {
67   freopen("!.in","r",stdin);
68   freopen("!.out","w",stdout);
69   int n,m,x,y,z;
70   LL tot1=0,tot2=0;
71   scanf("%d%d",&n,&m);
72   memset(head,-1,sizeof(head));
73   int s=0,t=n+1;
74   for(int i=1;i<=n;i++)
75     scanf("%d%d",&x,&y),add(s,i,x),add(i,s,0),add(i,t,y),add(t,i,0),tot1+=x+y;
76   for(int i=1;i<=m;i++)
77     scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,0),add(y,x,z),add(x,y,0),tot2+=z;
78   printf("%lld",tot1-dinic(s,t)+tot2);
79   return 0;
80 }

 


posted @ 2017-03-24 21:02  嘘丶  阅读(178)  评论(0编辑  收藏  举报