您的位置:首页 > 其它

BZOJ 2521 最小生成树(最小割)

2016-06-13 17:22 225 查看
http://www.lydsy.com/JudgeOnline/problem.php?id=2521

题意:每次能增加一条边的权值1,求最小代价让一条边保证在最小生成树里

思路:如果两个点中有环,那么这条边必须不能是环的最大边,这样子把之前所有的边权值变成V+1-v[i],无向图网络流就可以了

#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#define inf 0x7fffffff
struct edge{
int u,v,w;
}e[200005];
int n,m,id,dis[200005],cnt[200005],tot,S,T,nodes;
int flow[200005],op[200005],next[200005],first[200005],go[200005];
int read(){
char ch=getchar();int t=0,f=1;
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
return t*f;
}
void insert(int x,int y,int z){
tot++;
go[tot]=y;
next[tot]=first[x];
first[x]=tot;
flow[tot]=z;
}
void add(int x,int y,int z){
insert(x,y,z);op[tot]=tot+1;
insert(y,x,0);op[tot]=tot-1;
}
void add2(int x,int y,int z){
insert(x,y,z);op[tot]=tot+1;
insert(y,x,z);op[tot]=tot-1;
}
int dfs(int x,int f){
if (x==T) return f;
int mn=nodes,sum=0;
for (int i=first[x];i;i=next[i]){
int pur=go[i];
if (flow[i]&&dis[pur]+1==dis[x]){
int save=dfs(pur,std::min(f-sum,flow[i]));
sum+=save;
flow[i]-=save;
flow[op[i]]+=save;
if (sum==f||dis[S]>=nodes) return sum;
}
if (flow[i]) mn=std::min(mn,dis[pur]);
}
if (sum==0){
cnt[dis[x]]--;
if (cnt[dis[x]]==0){
dis[S]=nodes;
}else{
dis[x]=mn+1;
cnt[dis[x]]++;
}
}
return sum;
}
int main(){
n=read();m=read();id=read();
S=0,T=n+1;nodes=n+2;
for (int i=1;i<=m;i++){
e[i].u=read();e[i].v=read();e[i].w=read();
}
add(S,e[id].u,inf);
add(e[id].v,T,inf);
for (int i=1;i<=m;i++)if (i!=id&&e[i].w<=e[id].w){
add2(e[i].u,e[i].v,e[id].w+1-e[i].w);
}
int ans=0;
while (dis[S]<nodes) ans+=dfs(S,inf);
printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: