程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> bzoj2561 最小生成樹

bzoj2561 最小生成樹

編輯:C++入門知識

bzoj2561 最小生成樹


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

 輸出一行一個整數表示最少需要刪掉的邊的數量。

Sample Input

3 2
3 2 1
1 2 3
1 2 2

Sample Output

1

HINT

 

對於20%的數據滿足N ≤ 10,M ≤ 20,L ≤ 20;

  對於50%的數據滿足N ≤ 300,M ≤ 3000,L ≤ 200;

  對於100%的數據滿足N ≤ 20000,M ≤ 200000,L ≤ 20000。

 

Source

2012國家集訓隊Round 1 day1


 

 

 

 

最小割的應用

對於某一條邊,如果邊權小於它的邊能使其兩個端點連通,則這條邊一定不會出現在最小生成樹中。最大生成樹同理。

所以問題轉化為,刪去最少的邊,使小於該邊權的邊不能使兩端點連通、大於該邊權的邊也不能使兩端點連通。

我們只需要分別建圖求最小割,並對兩次結果取和。


 

 

 

#include
#include
#include
#include
#include
#include
#include
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define pa pair
#define maxn 20005
#define maxm 200005
#define inf 1000000000
using namespace std;
int n,m,s,t,w,ans=0,cnt;
int head[maxn],cur[maxn],dis[maxn];
struct edge_type
{
	int to,next,v;
}e[maxm*2];
struct edge
{
	int x,y,v;
}a[maxm];
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void add_edge(int x,int y,int v)
{
	e[++cnt]=(edge_type){y,head[x],v};head[x]=cnt;
	e[++cnt]=(edge_type){x,head[y],v};head[y]=cnt;
}
inline bool bfs()
{
	queueq;
	memset(dis,-1,sizeof(dis));
	dis[s]=0;q.push(s);
	while (!q.empty())
	{
		int tmp=q.front();q.pop();
		if (tmp==t) return true;
		for(int i=head[tmp];i;i=e[i].next) if (e[i].v&&dis[e[i].to]==-1)
		{
			dis[e[i].to]=dis[tmp]+1;
			q.push(e[i].to);
		}
	}
	return false;
}
inline int dfs(int x,int f)
{
	int tmp,sum=0;
	if (x==t) return f;
	for(int &i=cur[x];i;i=e[i].next)
	{
		int y=e[i].to;
		if (e[i].v&&dis[y]==dis[x]+1)
		{
			tmp=dfs(y,min(f-sum,e[i].v));
			e[i].v-=tmp;e[i^1].v+=tmp;sum+=tmp;
			if (sum==f) return f;
		}
	}
	if (!sum) dis[x]=-1;
	return sum;
}
inline void dinic()
{
	while (bfs())
	{
		F(i,1,n) cur[i]=head[i];
		ans+=dfs(s,inf);
	}
}
inline bool cmp(edge a1,edge a2)
{
	return a1.vw) add_edge(a[i].x,a[i].y,1);
		else break;
	}
	dinic();
	printf("%d\n",ans);
}


 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved