世界真的很大
这道题的方法还是比较神奇
认真想一下说不定还是能想出来,如果能结合起来好好想想
。。。
略有遗憾
但是学会了还是学会了,这是好事嘛
看题先:
description
给定一个边带正权的连通无向图G=(V,E),其中N=|V|,M=|E|,N个点从1到N依次编号,给定三个正整数u,v,和L (u≠v),假设现在加入一条边权为L的边(u,v),那么需要删掉最少多少条边,才能够使得这条边既可能出现在最小生成树上,也可能出现在最大生成树上?
input
第一行包含用空格隔开的两个整数,分别为N和M;
接下来M行,每行包含三个正整数u,v和w表示图G存在一条边权为w的边(u,v)。
最后一行包含用空格隔开的三个整数,分别为u,v,和 L;
数据保证图中没有自环。
output
输出一行一个整数表示最少需要删掉的边的数量。
最大生成树和最小生成树是差不多的,所以我们先考虑最小生成树的情况
对于这条给出的边,其连接的两点在一颗最小生成树上肯定是联通的,如果要使得这条边出现在最小生成树上,就需要比最小生成树上的边权值小
那我们就把所有权值比这条边小的选出来,如果要删起码会删这些边,删权值比其大的删了也没什么用
如果这些边能够使得u,v两点连通,那么就已经有一颗比这条边小的最小生成树了
这条边会出现在最小生成树上,当且仅当比他小的那些边不能使得u和v连通,这条边才有必要出现
那么题目等价于割最少的边使得u,v分开到两个集合里
给每条边付权值为1的话,就是最小割了
虽然数据范围大了一点,但是网络流据说对于流量为1的边是很快的
最大生成树同理
完整代码:
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int INF=0x3f3f3f3f;
struct edge
{
int u,v,w,last;
}ed[1000010],sid[1000010];
queue <int> state ;
int n,m,num=1,S,T,W,ans=0;
int head[1000010],dis[1000010];
void add(int u,int v,int w)
{
num++;
ed[num].v=v;
ed[num].w=w;
ed[num].last=head[u];
head[u]=num;
}
bool bfs()
{
while(!state.empty()) state.pop();
memset(dis,-1,sizeof(dis));
dis[S]=0;
state.push(S);
while(!state.empty())
{
int u=state.front();
state.pop();
for(int i=head[u];i;i=ed[i].last)
{
int v=ed[i].v;
if(dis[v]==-1 && ed[i].w)
{
dis[v]=dis[u]+1;
state.push(v);
}
}
}
return dis[T]!=-1;
}
int dfs(int u,int low)
{
if(u==T || low==0) return low;
int a=0;
for(int i=head[u];i;i=ed[i].last)
{
int v=ed[i].v;
if(dis[v]==dis[u]+1 && ed[i].w)
{
int tmp=dfs(v,min(low,ed[i].w));
ed[i].w-=tmp,ed[i^1].w+=tmp;
a+=tmp,low-=tmp;
if(low==0) return a;
}
}
if(low) dis[u]=-1;
return a;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&sid[i].u,&sid[i].v,&sid[i].w);
scanf("%d%d%d",&S,&T,&W);
for(int i=1;i<=m;i++)
if(sid[i].w<W)
add(sid[i].u,sid[i].v,1),add(sid[i].v,sid[i].u,0),
add(sid[i].v,sid[i].u,1),add(sid[i].u,sid[i].v,0);
while(bfs())
ans+=dfs(S,INF);
num=1;
memset(head,0,sizeof(head));
for(int i=1;i<=m;i++)
if(sid[i].w>W)
add(sid[i].u,sid[i].v,1),add(sid[i].v,sid[i].u,0),
add(sid[i].v,sid[i].u,1),add(sid[i].u,sid[i].v,0);
while(bfs())
ans+=dfs(S,INF);
printf("%d\n",ans);
return 0;
}
嗯,就是这样