题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6598
题意:
现在有n个士兵和m对关系,每个士兵都有一个不是战士就是法师的职业,每对关系给出两个士兵的下标x,y,和三个值 a,b,c,表示 如果x和y都同时为战士,那么会得到a的权值,如果同时都为法师,那么会得到c的权值,否则得到b的权值,问你该如何选择使得得到的权值最大。
做法:
队友刚看到的时候以为是一道dp题,我也就没摸到这道题了,只能说网络流的考法真的是多种多样,哪怕提示了你除三除四什么的应该也不能一下子想到,但是最小割这个概念确实是没的说的。如果都选择战士,那么失去的(割掉的)就是c和d那条边,加起来就是损失的b和c权值,也不知道为什么之前一直T,也不知道改改哪里就过了。。神奇的很。。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(int)a;i<=(int)b;i++)
using namespace std;
typedef long long ll;
const int maxn = 505;
const int maxm=100005;
const int MAX = 1<<26;
ll ans;
int n,m,cnt,head[maxn],d[maxn],sp,tp;//原点,汇点
int frs[maxn],tot[maxn],cap[maxm],nex[maxm],to[maxm];
//理论复杂度n2*m
void add(int u,int v,int c){
to[cnt]=v; cap[cnt]=c;
nex[cnt]=head[u]; head[u]=cnt++;
to[cnt]=u; cap[cnt]=0;
nex[cnt]=head[v]; head[v]=cnt++;
}
int bfs(){
queue <int> q;
memset(d,-1,sizeof(d));
d[sp]=0;
q.push(sp);
while(!q.empty()){
int cur=q.front();
q.pop();
for(int i=head[cur];i!=-1;i=nex[i]){
int u=to[i];
if(d[u]==-1 && cap[i]>0){
d[u]=d[cur]+1;
q.push(u);
}
}
}
return d[tp] != -1;
}
ll dfs(int a,ll b){
ll r=0;
if(a==tp)return b;
for(int i=head[a];i!=-1 && r<b;i=nex[i])
{
int u=to[i];
if(cap[i]>0 && d[u]==d[a]+1)
{
ll x=min((ll)cap[i],b-r);
x=dfs(u,x);
r+=x;
cap[i]-=x;
cap[i^1]+=x;
}
}
if(!r)d[a]=-2;
return r;
}
ll dinic(int sp,int tp){
ll total=0;int t;
while(bfs()){
while(t=dfs(sp,MAX))
total+=t;
}
return total;
}
int main(){
int i,u,v,c,x;
while(~scanf("%d%d",&n,&m)){
cnt=0; ans=0;
sp=0,tp=n+1;
memset(head,-1,sizeof(head));
memset(frs,0,sizeof(frs));
memset(tot,0,sizeof(tot));
for(int i=1;i<=m;i++){
int u,v;
ll A,B,C;
scanf("%d%d%lld%lld%lld",&u,&v,&A,&B,&C);
ll a=(A+B),b=(B+C),c=A+C-2*B;
ans=ans+A+B+C;
frs[u]+=a,frs[v]+=a;
tot[u]+=b,tot[v]+=b;
add(u,v,c); add(v,u,c);
}
rep(i,1,n){
if(frs[i]) add(sp,i,frs[i]);
if(tot[i]) add(i,tp,tot[i]);
}
ll sub=dinic(sp,tp);
printf("%lld\n",ans-sub/2);
}
return 0;
}