列表

详情


NC212292. 最小生成树

描述

给定一个边带正权的连通无向图G=(V,E),其中N=|V|,M=|E|,N个点从1到N依次编号,给定三个正整数u,v,和L (u≠v),假设现在加入一条边权为L的边(u,v),那么需要删掉最少多少条边,才能够使得这条边既可能出现在最小生成树上,也可能出现在最大生成树上?

输入描述

第一行包含用空格隔开的两个整数,分别为N和M;
接下来M行,每行包含三个正整数u,v和w表示图G存在一条边权为w的边(u,v)。
最后一行包含用空格隔开的三个整数,分别为u,v,和 L;
数据保证图中没有自环。

输出描述

输出一行一个整数表示最少需要删掉的边的数量。

示例1

输入:

3 2
3 2 1
1 2 3
1 2 2

输出:

1

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 129ms, 内存消耗: 7684K, 提交时间: 2020-09-30 20:21:02

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=2e4+5,M=2e5+5,Inf=1e9;
struct Graph{int u,v,w;}gra[M];
struct Edge{int to,f,nxt;}e[M<<1];
int n,m,fst[N],tote,lev[N],nf[N],s,t,l,ans;
void adde(int u,int v,int f){e[++tote]=(Edge){v,f,fst[u]};fst[u]=tote;}
bool bfs(){
	queue<int>que;
	memset(lev,-1,sizeof(lev));
	que.push(s);lev[s]=0;
	while(!que.empty()){
		int u=que.front();que.pop();
		for(int i=fst[u],v;~i;i=e[i].nxt)if(e[i].f&&lev[v=e[i].to]<0)
			lev[v]=lev[u]+1,que.push(v);
	}
	return lev[t]>=0;
}
int dfs(int u,int lim){
	if(u==t)return lim;
	int flow=0;
	for(int i=nf[u],v,f,tmp;~i;i=e[i].nxt){
		v=e[i].to;f=e[i].f;
		if(f&&lev[v]==lev[u]+1){
			tmp=dfs(v,min(lim,f));
			e[i].f-=tmp;e[i^1].f=tmp;lim-=tmp;flow+=tmp;
			if(!lim){nf[u]=i;return flow;}
		}
	}
	nf[u]=-1;return flow;
}
void init(){memset(fst,-1,sizeof(fst));tote=1;}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)scanf("%d%d%d",&gra[i].u,&gra[i].v,&gra[i].w);
	scanf("%d%d%d",&s,&t,&l);init();
	for(int i=1;i<=m;i++)if(gra[i].w<l)adde(gra[i].u,gra[i].v,1),adde(gra[i].v,gra[i].u,1);
	while(bfs()){
		for(int i=1;i<=n;i++)nf[i]=fst[i];
		ans+=dfs(s,Inf);
	}
	init();
	for(int i=1;i<=m;i++)if(gra[i].w>l)adde(gra[i].u,gra[i].v,1),adde(gra[i].v,gra[i].u,1);
	while(bfs()){
		for(int i=1;i<=n;i++)nf[i]=fst[i];
		ans+=dfs(s,Inf);
	}
	printf("%d\n",ans);
	return 0;
}

上一题