1. 程式人生 > >bzoj 2561: 最小生成樹

bzoj 2561: 最小生成樹

online std urn 直接 stat bre 一行 add accept

2561: 最小生成樹

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 2248 Solved: 1073
[Submit][Status][Discuss]

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

首先我們要明確一個最小生成樹的性質(貌似是切割性質還是啥的忘了), 那就是如果一條邊在它所在的任意環裏都是最小的話,那麽它肯定是在最小生成樹中的;反之亦然。 最大生成樹的情況類似。 如果要讓這條邊在最小生成樹中,那麽它和比它小的邊所構成的圖中不能有環,也就是u和v除了這條直接連接的邊沒有路徑聯通。 這不就是u到v的最小割嗎? 最大生成樹的情況類似,而且非常好的一點是, 所有比(u,v)小的邊和比(u,v)大的邊是相互獨立的, 這就提示我們可以單獨求解,最後加起來就行了。
/*
************************************************************* Problem: 2561 User: JYYHH Language: C++ Result: Accepted Time:1332 ms Memory:18980 kb ****************************************************************/ #include<bits/stdc++.h> #define ll long long #define maxn 40005 #define
pb push_back using namespace std; const int inf=1<<29; vector<int> g[maxn]; struct lines{ int to,flow,cap; }l[maxn*20]; int t=-1,S,T,n; int d[maxn],cur[maxn]; bool v[maxn]; inline void add(int xx,int yy,int zz){ l[++t]=(lines){yy,0,zz},g[xx].pb(t); l[++t]=(lines){xx,0,0},g[yy].pb(t); } inline bool bfs(){ queue<int> q; memset(v,0,sizeof(v)); d[S]=0,v[S]=1,q.push(S); int x; lines e; while(!q.empty()){ x=q.front(),q.pop(); for(int i=g[x].size()-1;i>=0;i--){ e=l[g[x][i]]; if(!v[e.to]&&e.flow<e.cap){ d[e.to]=d[x]+1; v[e.to]=1; q.push(e.to); } } } return v[T]; } int dfs(int x,int a){ if(x==T||!a) return a; int flow=0,f,sz=g[x].size(); for(int &i=cur[x];i<sz;i++){ lines &e=l[g[x][i]]; if(d[x]==d[e.to]-1&&(f=dfs(e.to,min(a,e.cap-e.flow)))){ flow+=f,a-=f; e.flow+=f,l[g[x][i]^1].flow-=f; if(!a) break; } } return flow; } inline int max_flow(){ int an=0; while(bfs()){ memset(cur,0,sizeof(cur)); an+=dfs(S,inf); } return an; } inline void init(){ for(int i=1;i<=n;i++) g[i].clear(); t=-1; } int m,W,ww[maxn*5]; int uu[maxn*5],vv[maxn*5]; int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d%d",uu+i,vv+i,ww+i); } scanf("%d%d%d",&S,&T,&W); int ans=0; for(int i=1;i<=m;i++) if(ww[i]<W){ add(uu[i],vv[i],1); add(vv[i],uu[i],1); } ans+=max_flow(); init(); for(int i=1;i<=m;i++) if(ww[i]>W){ add(uu[i],vv[i],1); add(vv[i],uu[i],1); } ans+=max_flow(); printf("%d\n",ans); return 0; }

bzoj 2561: 最小生成樹