zoukankan      html  css  js  c++  java
  • 洛谷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('
    ')
    	#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;
    }
    
  • 相关阅读:
    SecureCRT8.3
    firewalld
    yum的repo文件详解、以及epel简介、yum源的更换、常用yum命令
    Softether使用本地网桥
    nginx应用geoip模块,实现不同地区访问不同页面的需求(实践版)
    iOS开发>学无止境
    iOS开发>学无止境
    iOS开发>学无止境
    iOS开发>学无止境
    Objective-C学习- appDelegate 生命周期
  • 原文地址:https://www.cnblogs.com/lgj-lgj/p/13052406.html
Copyright © 2011-2022 走看看