[FZOJ190] 网络流+二分答案

[FZOJ190]

  • 难点在建图
  • 建分层图,拆点,从一层走到另一层代表当前走的路径长度增加了1
  • 二分答案,代表最短路最大是多少
  • 从起点开始求一个最小割
  • 把属于最小割的边ban掉,就相当于选中了这个点,及花费增加1,只有这样才能使最短路增加1
  • 画个图感性理解一下
  • 思路太神仙了,这题就当板子用吧
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define S(i,j) (j+(i-1)*2*n)
#define T(i,j) (j+(i-1)*2*n+n)
using namespace std;
const int oo=1e9;
const int N=1e5;
struct node{int y,n,v;}e[N*50];
struct Q{int x,y;}a[N];
int s,t,n,m,k,l,r,mid,ans=0,len=1,d[N],lin[N];
void read(int x,int y,int v)
{e[++len].y=y,e[len].v=v,e[len].n=lin[x],lin[x]=len;}
void add(int x,int y,int v)
{read(x,y,v),read(y,x,0);}
bool bfs(int s){
	queue<int> q;
	memset(d,0,sizeof(d));
	q.push(s),d[s]=1;
	while(q.size()){
		int x=q.front();q.pop();
		for(int i=lin[x];i;i=e[i].n){
			int y=e[i].y;
			if(d[y]||e[i].v==0)continue;
			d[y]=d[x]+1;
			q.push(y);
		}
	}return d[t]>0;
}
int dfs(int x,int minf){
	int sum=0,flow=0;
	if(x==t)return minf;
	for(int i=lin[x];i;i=e[i].n){
		int y=e[i].y;
		if(d[y]==d[x]+1&&e[i].v){
			flow=dfs(y,min(minf,e[i].v));
			if(!flow)d[y]=0;
			sum+=flow,minf-=flow,e[i].v-=flow,e[i^1].v+=flow;
			if(!minf)return sum;
		}
	}return sum;
}
void init(){
	memset(lin,0,sizeof(lin));
	len=1;
}
bool judge(int mid){
	init();
	rep(i,1,mid+1){
		rep(j,2,n-1)add(S(i,j),T(i,j),1);
		if(i!=mid+1){
			add(S(i,n),S(i+1,n),oo);
			rep(j,2,n-1)add(S(i,j),T(i+1,j),oo);
			rep(j,1,m){
				add(T(i,a[j].y),S(i+1,a[j].x),oo);
				add(T(i,a[j].x),S(i+1,a[j].y),oo);
			}	
		}
	}
	s=T(1,1),t=S(mid+1,n);
	int ans=0;
	while(bfs(s)){
		ans+=dfs(s,oo);
		if(ans>k)return 0;
	}
	return ans<=k;
} 
int main()
{
	freopen("min.in","r",stdin);
	freopen("min.out","w",stdout);
	scanf("%d%d%d",&n,&m,&k);
	rep(i,1,m){
		scanf("%d%d",&a[i].x,&a[i].y);
		a[i].x++,a[i].y++;
	}
	l=0,r=2*n;
	while(l<=r){
		mid=l+r>>1;
		if(judge(mid))ans=mid,l=mid+1;
		else r=mid-1;
	}
	printf("%d\n",ans+1);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/strangeDDDF/article/details/88042382