bzoj2229 最小割 分治&网络流

       做过ZJOI2016(QAQ)的旅行者之后这道题目就变成一眼出的题了。。。

       首先选两个点跑最小割更新答案,然后把和S连在一起的递归下去,和T连在一起的递归下去就好了。。但是不会证明。。。。。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 205
#define M 6005
using namespace std;

int n,m,tot,sta,gol,fst[N],cur[N],pnt[M],len[M],nxt[M],d[N],h[N],num[N],fa[N],a[N],b[N],c[N][N];
bool vis[N];
void add(int x,int y,int z){
	pnt[++tot]=y; len[tot]=z; nxt[tot]=fst[x]; fst[x]=tot;
}
void bfs(){
	memset(num,0,sizeof(num));
	memset(d,0x3f,sizeof(d)); d[gol]=0;
	int head=0,tail=1; h[1]=gol;
	while (head<tail){
		int x=h[++head],p; num[d[x]]++;
		for (p=fst[x]; p; p=nxt[p]) if (len[p^1]){
			int y=pnt[p];
			if (d[x]+1<d[y]){
				d[y]=d[x]+1; h[++tail]=y;
			}
		}
	}
}
int up(){
	int i,tmp=1000000000;
	for (i=gol; i!=sta; i=pnt[fa[i]^1]) tmp=min(tmp,len[fa[i]]);
	for (i=gol; i!=sta; i=pnt[fa[i]^1]){
		len[fa[i]]-=tmp; len[fa[i]^1]+=tmp;
	}
	return tmp;
}
int isap(){
	int i;
	for (i=2; i<=tot; i++){ len[i]=len[i^1]=(len[i]+len[i^1])>>1; }
	bfs(); memcpy(cur,fst,sizeof(fst));
	int x=sta,flow=0,p; bool flag;
	while (d[x]<n){
		if (x==gol){ flow+=up(); x=sta; }
		flag=1;
		for (p=cur[x]; p; p=nxt[p]) if (len[p]){
			int y=pnt[p];
			if (d[y]+1==d[x]){
				fa[y]=cur[x]=p; x=y;
				flag=0; break;
			}
		}
		if (flag){
			int mn=n-1; cur[x]=fst[x];
			for (p=fst[x]; p; p=nxt[p])
				if (len[p]) mn=min(mn,d[pnt[p]]);
			num[d[x]]--; if (!num[d[x]]) break;
			d[x]=mn+1; num[d[x]]++;
			if (x!=sta) x=pnt[fa[x]^1];
		}
	}
	return flow;
}
void dfs(int x){
	vis[x]=1; int p;
	for (p=fst[x]; p; p=nxt[p]) if (len[p] && !vis[pnt[p]]) dfs(pnt[p]);
}
void solve(int l,int r){
	if (l==r) return;
	sta=a[l]; gol=a[r]; int flow=isap(),i,j;
	memset(vis,0,sizeof(vis)); dfs(sta);
	for (i=1; i<=n; i++) if (vis[i])
		for (j=1; j<=n; j++) if (!vis[j])
			c[j][i]=c[i][j]=min(c[i][j],flow);
	int x=l,y=r;
	for (i=l; i<=r; i++)
		if (vis[a[i]]) b[x++]=a[i]; else b[y--]=a[i];
	for (i=l; i<=r; i++) a[i]=b[i];
	if (l<x) solve(l,x-1); if (y<r) solve(y+1,r);
}
int main(){
	int cas; scanf("%d",&cas);
	while (cas--){
		scanf("%d%d",&n,&m); int i,x,y,z;
		tot=1; memset(fst,0,sizeof(fst));
		memset(c,0x3f,sizeof(c));
		for (i=1; i<=m; i++){
			scanf("%d%d%d",&x,&y,&z);
			add(x,y,z); add(y,x,z);
		}
		for (i=1; i<=n; i++) a[i]=i; solve(1,n);
		scanf("%d",&m);
		while (m--){
			int ans=0,j; scanf("%d",&x);
			for (i=2; i<=n; i++)
				for (j=1; j<i; j++) if (c[i][j]<=x) ans++;
			printf("%d\n",ans);
		}
		puts("");
	}
	return 0;
}


by lych

2016.4.15

你可能感兴趣的:(分治,DFS,网络流,最大流,isap)