【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); } }
相关文章推荐
- 【JZOJ100003】【NOI2017模拟.4.1】 Tree
- [JZOJ100003]【NOI2017模拟.4.1】 Tree
- 【JZOJ100005】【NOI2017模拟.4.1】Shoes
- hdu 1055 & poj 2054 Color a Tree 树&贪心 找最大费用点和父节点合并
- 【JZOJ100005】【NOI2017模拟.4.1】Shoes
- 【NOI2017模拟.4.1】Shoes【DP决策单调性,主席树,分治】
- [雅礼4-4]Tree 最大费用循环流
- 【NOI2017模拟.4.1】 Dice【概率,期望,DP,精度优化】
- (vijos 1892 noip 模拟 tree)<树形DP求树的最大匹配及方案数>
- 【JZOJ100004】【NOI2017模拟.4.1】 Dice
- 【JZOJ100004】【NOI2017模拟.4.1】 Dice
- [JZOJ100004]【NOI2017模拟.4.1】 Dice
- 1035 火车停留 最大费用最大流
- HDU 3395 Special Fish 最“大”费用最大流
- POJ 3680 最大费用流
- [模版] 网络流最大流、费用流
- oracle open_cursors的含义及ORA-01000: 超出打开游标的最大数模拟
- Xcode 4.1实用小工具:模拟网络连接和带宽
- hdu2686--Matrix(拆点+最大费用)
- 1402 最大值(模拟)