BZOJ 2561 - 最小生成树 + 最小割

本题需要用一点M(in & ax)ST的性质。。

以MinestST(这英语也是十级水平。。)为例。。假设加入边(u, v),边权为L。然后我们把所有边权小于L的边都取出来单独看。这些边不能连通u, v,否则(u,v)边绝无可能在MST中——因为在加入它之后形成的这个环中,如果去掉它,显然是最优的。

所以以u、v为s、t,每条边权小于L的边容量置为1、跑一遍无向图最小割即可。。

MaxestST同理。。答案只需两次相加(因为不会统计到重复的边)。。

武神提了一个问题。。竟被吓到。。无向图最小割是什么鬼

怎么建图?难道要拆成两个方向建四条弧!?

不用。。只要建一个方向。。因为两个方向上不可能有同时有流量。。

Solved...

// BZOJ 2561

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

 const int N=20000+5, M=200000*2+5, INF=0x7f7f7f7f;

 #define rep(i,a,b) for (int i=a; i<=b; i++)
 #define dep(i,a,b) for (int i=a; i>=b; i--)
 #define read(x) scanf("%d", &x)
 #define fill(a,x) memset(a, x, sizeof(a))

 struct Edge {
 	int from, to, dis;
 	bool operator < (const Edge &x) const { return dis<x.dis; }
 } e[M/2];

 struct Graph {
 	int s, from[M], to[M], cap[M], pre[M], last[N];
 	void init() { s=-1; fill(last, -1); }
 	void ine(int a, int b, int c) {
 		s++;
 		from[s]=a, to[s]=b, cap[s]=c, pre[s]=last[a];
 		last[a]=s;
 	}
 	void ine2(int a, int b, int c1, int c2) {
 		ine(a, b, c1);
 		ine(b, a, c2);
 	}
 } G;
 #define reg(i,s,u) for (int i=s.last[u]; i!=-1; i=s.pre[i])

 int Q[N*4], d[N], cur[N], n, m, u, v, w;
 bool vis[N];

 bool BFS(int s, int t) {
 	int head=1, tail=1;
 	fill(vis, false);
 	Q[1]=s; d[s]=0; vis[s]=true;
 	while (head<=tail) {
 		int x=Q[head++];
 		reg(i,G,x) {
 			int y=G.to[i];
 			if (G.cap[i]<=0 || vis[y]) continue;
 			vis[y]=true;
 			d[y]=d[x]+1;
 			Q[++tail]=y;
 		}
 	} 
 	return vis[t];
 }

 int DFS(int x, int t, int a) {
 	if (x==t || a==0) return a;
 	int ret=0, flow;
 	for (int &i=cur[x]; i!=-1; i=G.pre[i]) {
 		int y=G.to[i];
 		if (d[y]==d[x]+1 && (flow=DFS(y, t, min(a, G.cap[i])))>0) {
 			G.cap[i]-=flow;
 			G.cap[i^1]+=flow;
 			a-=flow;
 			ret+=flow;
 			if (a==0) break;  // 这个break不能往前写!
 		}
 	}
 	return ret;
 }

 int Dinic(int s, int t) {
 	int ret=0;
 	while (BFS(s, t)) {
 		rep(i,1,n) cur[i]=G.last[i];
 		ret+=DFS(s, t, INF);
 	}
 	return ret;
 }

int main()
{
	read(n); read(m);
	rep(i,1,m) read(e[i].from), read(e[i].to), read(e[i].dis);

    int ans=0;
    sort(e+1, e+m+1);
	read(u), read(v), read(w);
	G.init();
	rep(i,1,m) if (e[i].dis<w) G.ine2(e[i].from, e[i].to, 1, 1); else break;
	ans+=Dinic(u, v);
    G.init();
    dep(i,m,1) if (e[i].dis>w) G.ine2(e[i].from, e[i].to, 1, 1); else break;
    ans+=Dinic(u, v);

    printf("%d\n", ans);
	
	return 0;
}


posted @ 2015-12-16 00:04  Armeria  阅读(203)  评论(0编辑  收藏  举报