bzoj 1738 [Usaco2005 mar]Ombrophobic Bovines 发抖的牛 最大流+二分

题目要求所有牛都去避雨的最长时间最小。

显然需要二分 二分之后考虑如何判定。

显然每头牛都可以去某个地方 但是前提是最短路径<=mid.

依靠二分出来的东西建图。可以发现这是一个匹配问题 dinic即可。

注意数组要开两倍 因为要拆点 我开小了wa了两发才意识过来。

const int MAXN=410;
int n,m,S,len,T,L,R,ans;
ll a[MAXN][MAXN];
int c[MAXN],cc[MAXN],cur[MAXN],vis[MAXN],q[MAXN];
int lin[MAXN],ver[MAXN*MAXN<<1],nex[MAXN*MAXN<<1],e[MAXN*MAXN<<1];
inline void add(int x,int y,int z)
{
	ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;
	ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=0;
}
inline int dinic(int x,int flow)
{
	if(x==T)return flow;
	int res=flow,k;
	for(int i=cur[x];i&&res;i=nex[i])
	{
		int tn=ver[i];cur[x]=i;
		if(vis[tn]==vis[x]+1&&e[i])
		{
			k=dinic(tn,min(e[i],res));
			if(!k){vis[tn]=0;continue;}
			e[i]-=k;e[i^1]+=k;res-=k;
		}
	}
	return flow-res;
}
inline int bfs()
{
	rep(1,T,i)vis[i]=0,cur[i]=lin[i];
	L=R=0;q[++R]=S;vis[S]=1;
	while(++L<=R)
	{
		int x=q[L];
		go(x)
		{
			if(vis[tn]||!e[i])continue;
			vis[tn]=vis[x]+1;
			q[++R]=tn;
			if(tn==T)return 1;
		}
	}
	return 0;
}
inline int check(ll x)
{
	len=1;
	memset(lin,0,sizeof(lin));
	rep(1,n,i)
	{
		rep(1,n,j)if(a[i][j]<=x)add(i,j+n,INF);
		add(S,i,c[i]);add(i+n,T,cc[i]);
	}
	int flow,sum=0;
	while(bfs())while((flow=dinic(S,INF)))sum+=flow;
	//cout<<sum<<endl;
	return sum>=ans;
}
int main()
{
	freopen("1.in","r",stdin);
	get(n);get(m);int cnt1=0;S=n<<1|1;T=S+1;
	rep(1,n,i)get(c[i]),cc[i]=read(),ans+=c[i],cnt1+=cc[i];
	if(ans>cnt1){puts("-1");return 0;}
	rep(1,n,i)rep(1,i,j)if(i!=j)a[j][i]=a[i][j]=P;
	rep(1,m,i)
	{
		int get(x);int get(y);int get(z);
		a[x][y]=a[y][x]=min(a[x][y],(ll)z);
	}
	rep(1,n,k)rep(1,n,i)rep(1,i,j)a[j][i]=a[i][j]=min(a[i][j],a[i][k]+a[k][j]);
	ll l=0,r=0;
	rep(1,n,i)rep(1,i,j)if(a[i][j]!=P)r=max(r,a[i][j]);
	if(!check(r)){puts("-1");return 0;}
	while(l<r)
	{
		ll mid=(l+r)>>1;
		if(check(mid))r=mid;
		else l=mid+1;
	}
	putl(l);return 0;
}
原文地址:https://www.cnblogs.com/chdy/p/12642961.html