洛谷P5039 最小生成树 题解

题目大意

给你一个带权无向连通图,边为 \((u_i,v_i,w_i)\),有一条边是特殊边,每次操作你可以选定一条边,除了特殊边之外的边边权全部减一,求最少操作几步使特殊边一定在最小生成树内

\(Solution:\)

考虑 \(Kruskal\) 最小生成树算法的原理,则显然对于任意一条边权大于特殊边的边,一定在特殊边之后加入生成树,不影响特殊边,则不予考虑
对于所有比特殊边边权 \(w\) 小的边,建图
考虑题目中的操作的意义,相对即为将特殊边的边权 \(+1\),那么只需将连接特殊边 \((u,v,w)\) 的端点 \(u,v\) 的边权调到 \(\geq w\) 即可,费用为 \(w_i-w+1\),即求以 \(u\) 为源点,\(v\)为汇点,每条边边权对应为 \(w_i-w+1\) 的图的最小割,在图上跑最大流即可,代码如下

\(Code:\)

#include<bits/stdc++.h>
using namespace std;
namespace my_std
{
	typedef long long ll;
	typedef double db;
	#define pf printf
	#define pc putchar
	#define fr(i,x,y) for(register int i=(x);i<=(y);++i)
	#define pfr(i,x,y) for(register int i=(x);i>=(y);--i)
	#define go(u) for(int i=head[u];i;i=e[i].nxt)
	#define enter pc('\n')
	#define space pc(' ')
	#define fir first
	#define sec second
	#define MP make_pair
	const int inf=0x3f3f3f3f;
	const ll inff=1e15;
	inline int read()
	{
		int sum=0,f=1;
		char ch=0;
		while(!isdigit(ch))
		{
			if(ch=='-') f=-1;
			ch=getchar();
		}
		while(isdigit(ch))
		{
			sum=sum*10+(ch^48);
			ch=getchar();
		}
		return sum*f;
	}
	inline void write(int x)
	{
		if(x<0)
		{
			x=-x;
			pc('-');
		}
		if(x>9) write(x/10);
		pc(x%10+'0');
	}
	inline void writeln(int x)
	{
		write(x);
		enter;
	}
	inline void writesp(int x)
	{
		write(x);
		space;
	}
}
using namespace my_std;
const int N=1e5+50;
int n,m,lab,s,t,val,head[N],vis[N],dep[N],cur[N],cnt,ans;
queue<int> q;
struct tmp
{
	int u,v,w;
}edge[N<<1];
struct edge
{
	int to,nxt,flow;
}e[N<<1];
inline void add(int u,int v,int w)
{
	e[++cnt].to=v;
	e[cnt].flow=w;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}
inline bool bfs(int s,int t)
{
	memset(dep,-1,sizeof(dep));
	memset(vis,0,sizeof(vis));
	while(!q.empty()) q.pop();
	q.push(s);
	vis[s]=dep[s]=1;
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		go(u)
		{
			int v=e[i].to;
			if(vis[v]||!e[i].flow) continue;
			vis[v]=1,dep[v]=dep[u]+1;
			q.push(v);
		}
	}
	if(dep[t]>0) return true;
	return false;
}
int dfs(int u,int low)
{
	if(u==t) return low;
	int curflow=0;
	go(u)
	{
		int v=e[i].to;
		if(dep[v]!=dep[u]+1||(!e[i].flow)) continue;
		if(!e[i].flow) continue;
		if(curflow=dfs(v,min(low,e[i].flow)))
		{
			e[i].flow-=curflow,e[i^1].flow+=curflow;
			return curflow;
		}
	}
	return 0;
}
int main(void)
{
	n=read(),m=read(),lab=read();
	fr(i,1,m)
	{
		int u=read(),v=read(),w=read();
		if(i==lab) s=u,t=v,val=w;
		else edge[i].u=u,edge[i].v=v,edge[i].w=w;
	}
	fr(i,1,m)
	{
		if(edge[i].w>val||i==lab) continue;
		add(edge[i].u,edge[i].v,val-edge[i].w+1);
		add(edge[i].v,edge[i].u,val-edge[i].w+1);
		add(edge[i].u,edge[i].v,0),add(edge[i].v,edge[i].u,0);
	}
	while(bfs(s,t)) ans+=dfs(s,inf);
	writeln(ans);
	return 0;
}
posted @ 2020-06-05 21:26  L_G_J  阅读(140)  评论(0编辑  收藏  举报