给你一个带权无向连通图,边为 \((u_i,v_i,w_i)\),有一条边是特殊边,每次操作你可以选定一条边,除了特殊边之外的边边权全部减一,求最少操作几步使特殊边一定在最小生成树内
考虑 \(Kruskal\) 最小生成树算法的原理,则显然对于任意一条边权大于特殊边的边,一定在特殊边之后加入生成树,不影响特殊边,则不予考虑
对于所有比特殊边边权 \(w\) 小的边,建图
考虑题目中的操作的意义,相对即为将特殊边的边权 \(+1\),那么只需将连接特殊边 \((u,v,w)\) 的端点 \(u,v\) 的边权调到 \(\geq w\) 即可,费用为 \(w_i-w+1\),即求以 \(u\) 为源点,\(v\)为汇点,每条边边权对应为 \(w_i-w+1\) 的图的最小割,在图上跑最大流即可,代码如下
#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;
}
原文:https://www.cnblogs.com/lgj-lgj/p/13052406.html