您的位置:首页 > 其它

【NOI2017模拟.4.1】 Tree【最大费用循环流】

2017-04-07 09:37 253 查看

Description



Solution

这题一看就是网络流,但是时无向图,无源汇……

最大费用循环流!

首先连边是很显然的,连成一个环就可以了,树上的边连双向(上下都能走),然后要覆盖一条链,那么这条链就从下往上连(其实上面连了双向,这里从下往上也可以)

然后直接套上最小费用循环流就可以了。

首先把所有的正权边都流满为ans

然后因为要流量平衡,所以要平衡一下。

统计一下现在的流量度数:

1、如果度数>0,S向i连边,流量为度数,费用0

2、如果度数<0,i向T连边,流量为-度数,费用0

原图的边流量和费用不变

然后跑一次最小费用最大流为ans1

因为后面的流量是来平衡的,所以要用ans-ans1为最终的答案。

Code

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define rep(i,a) for(i=first[a];i;i=next[i])
#define rep1(i,a) for(i=first1[a];i;i=next1[i])
using namespace std;
typedef long long ll;
const int maxn=1e5+7,inf=0x7fffffff;
ll i,j,k,l,t,n,m,ans,cas;
ll first[maxn*2],last[maxn*2],next[maxn*2],chang[maxn*2],cost[maxn*2],d[maxn*2],num;
ll first1[maxn*2],last1[maxn*2],next1[maxn*2],chang1[maxn*2],num1,fan[maxn*2];
ll S,T,id,bz[maxn],ans1,deep[maxn],du[maxn];
bool yi,cz,lian;
struct node{
ll u,v,c;
}a[maxn];
bool cmp(node x,node y){
return x.u<y.u;
}
void add(ll x,ll y,ll z,ll o){
last[++num]=y,next[num]=first[x],first[x]=num,chang[num]=z,cost[num]=o,fan[num]=num+1;
last[++num]=x,next[num]=first[y],first[y]=num,chang[num]=0,cost[num]=-o,fan[num]=num-1;
}
void add1(ll x,ll y,ll z){
last1[++num1]=y,next1[num1]=first1[x],first1[x]=num1,chang1[num1]=z;
}
void dfs(ll x,ll y){
int i;
deep[x]=deep[y]+1;
rep1(i,x){
if(last1[i]!=y){
add(x,last1[i],chang1[i],0);
add(last1[i],x,chang1[i],0);
//   du[x]+=chang1[i],du[last1[i]]-=chang1[i];
dfs(last1[i],x);
}
}
}
int zkw(ll x,ll y,ll z){
if(!y)return 0;
if(x==T){ans1+=y*z;return y;}
int i,j,k=0;
bz[x]=id;
rep(i,x){
if(bz[last[i]]!=id&&chang[i]&&d[x]==d[last[i]]+cost[i]){
j=zkw(last[i],min(y,chang[i]),z+cost[i]);
if(j){
chang[i]-=j,chang[fan[i]]+=j;
k+=j,y-=j;
if(!y)break;
}
}
}
return k;
}
bool pan(){
ll i,j,k,o=inf;
if(!id)return 1;
fo(i,S,T){
if(bz[i]==id){
rep(j,i){
if(bz[last[j]]!=id&&chang[j])o=min(o,d[last[j]]-d[i]+cost[j]);
}
}
}
if(o==inf)return 0;
fo(i,S,T)if(bz[i]==id)d[i]+=o;
return 1;
}
int main(){
//  freopen("tree.in","r",stdin);
//  freopen("tree.out","w",stdout);
freopen("fan.in","r",stdin);
for(scanf("%d",&cas);cas;cas--){
scanf("%d%d",&n,&m);
ans=ans1=0;
memset(first,0,sizeof(first));num=num1=0;memset(first1,0,sizeof(first1));
memset(du,0,sizeof(du));memset(d,0,sizeof(d));memset(deep,0,sizeof(deep));
memset(bz,0,sizeof(bz));
S=0,T=n+1;
fo(i,1,n-1){
scanf("%d%d%d",&k,&l,&t);
add1(k,l,t),add1(l,k,t);
}
dfs(1,0);
fo(i,1,m){
scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].c);
if(deep[a[i].u]<deep[a[i].v])swap(a[i].u,a[i].v);
du[a[i].u]++,du[a[i].v]--;
ans+=a[i].c;
add(a[i].u,a[i].v,1,a[i].c);
}
fo(i,1,n){
if(du[i]>0)add(S,i,du[i],0);
else if(du[i]<0)add(i,T,-du[i],0);
}
id=0;
while(pan()){
id++;
while(zkw(S,inf,0))id++;
}
printf("%lld\n",ans-ans1);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: