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 }