题面
解析
看上去是黑题啊!
实际上也就是道网络流最大流。
当然,我们也知道网络流最关键的是建图。
首先,分析一下题目:
题目要求在操作后使给定的边lab一定在最小生成树上,
求最小的操作数。
先设lab连通的边为A,B。
那么,根据Krustal算法,在加入lab时一定没有权值比lab小的边使A,B连通。
所以,只要将权值比lab小的边重新建图,
将容量设为这条边最少的操作次数就行了。
而最小的操作次数就应该是wlab −wi +1。
最后求A到B的最小割(最大流)就行了。
上AC代码:
#include<bits/stdc++.h> using namespace std; inline int read(){ int sum=0,f=1;char ch=getchar(); while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();} return f*sum; } const int INF=0x3f3f3f3f; struct road{ int next,to,w; }e[100001]; struct line{ int x,y,w; }a[100001]; int n,m,lab; int s,t; int head[10001],cnt=1; int d[100001],v[100001]; void add(int x,int y,int w){ e[++cnt].to=head[x]; e[cnt].next=y; e[cnt].w=w; head[x]=cnt; } bool bfs(){ memset(d,-1,sizeof(d)); memset(v,0,sizeof(v)); queue <int> que; que.push(s); v[s]=1; d[s]=1; while(!que.empty()){ int x=que.front(); que.pop(); for(int i=head[x];i;i=e[i].to){ int k=e[i].next; if(v[k]||!e[i].w) continue; v[k]=1; d[k]=d[x]+1; que.push(k); } } if(d[t]>0) return 1; return 0; } int dfs(int x,int low){ if(x==t) return low; int c=0; for(int i=head[x];i;i=e[i].to){ int k=e[i].next; if(d[k]!=d[x]+1) continue; if(!e[i].w) continue; if((c=dfs(k,min(low,e[i].w)))){ e[i].w-=c; e[i^1].w+=c; return c; } } return 0; } void DINIC(){ int ans=0,mi; while(bfs()){ while((mi=dfs(s,INF))) ans+=mi; } printf("%d ",ans); return ; } int main(){ // freopen("mst.in","r",stdin); // freopen("mst.out","w",stdout); n=read();m=read();lab=read(); for(int i=1;i<=m;i++){ a[i].x=read();a[i].y=read();a[i].w=read(); } s=a[lab].x;t=a[lab].y; for(int i=1;i<=m;i++){ if(a[i].w<=a[lab].w&&i!=lab){ add(a[i].x,a[i].y,a[lab].w-a[i].w+1); add(a[i].y,a[i].x,0); add(a[i].y,a[i].x,a[lab].w-a[i].w+1); add(a[i].x,a[i].y,0); } } DINIC(); return 0; }