1. 程式人生 > >poj 2112 (最大流+二分)

poj 2112 (最大流+二分)

題意:有k臺擠奶機,c頭奶牛,給出這k+c個實體間的距離,求出每頭奶牛都到一臺擠奶機去,怎麼分配使奶牛走的最大距離最小。

用二分列舉最大距離,,,,

#include<stdio.h>
#include<string.h>
#define N 500
#define inf 0x3fffffff
int map[N][N],dis[N],gap[N],head[N],num,n,m,D,start,end,ans;
struct edge
{
	int st,ed,flow,next;
}E[N*40];
void addedge(int x,int y,int w)
{
	E[num].st=x;E[num].ed=y;E[num].flow=w;E[num].next=head[x];head[x]=num++;
	E[num].st=y;E[num].ed=x;E[num].flow=0;E[num].next=head[y];head[y]=num++;
}
int dfs(int u,int minflow)
{
	if(u==end)return minflow;
	int i,v,f,min_dis=ans-1,flow=0;
	for(i=head[u];i!=-1;i=E[i].next)
	{
		if(E[i].flow>0)
		{
			v=E[i].ed;
			if(dis[v]+1==dis[u])
			{
				f=dfs(v,E[i].flow>minflow-flow?minflow-flow:E[i].flow);
				E[i].flow-=f;
				E[i^1].flow+=f;
				flow+=f;
				if(flow==minflow)break;
				if(dis[start]>=ans)return flow;
			}
			min_dis=min_dis>dis[v]?dis[v]:min_dis;
		}
	}
	if(flow==0)
	{
		if(--gap[dis[u]]==0)
			dis[start]=ans;
		dis[u]=min_dis+1;
		gap[dis[u]]++;
	}
	return flow;
}
int isap()
{
	int maxflow=0;
	memset(dis,0,sizeof(dis));
	memset(gap,0,sizeof(gap));
	gap[0]=ans;
	while(dis[start]<ans)
		maxflow+=dfs(start,inf);
	return maxflow;
}
void makemap(int DD)
{
	int i,j;
	memset(head,-1,sizeof(head));
	num=0;
	for(i=1;i<=m;i++)
		addedge(start,i+n,1);
	for(i=1;i<=n;i++)
		addedge(i,end,D);
	for(i=n+1;i<=n+m;i++)
		for(j=1;j<=n;j++)
		{
			if(map[i][j]<=DD&&map[i][j]!=0)
				addedge(i,j,1);
		}
}
int main()
{
	int i,j,k,left,right,mid;
	while(scanf("%d%d%d",&n,&m,&D)!=-1)
	{
		left=0;right=0;start=0;end=n+m+1;ans=end+1;
		memset(map,0,sizeof(map));
		for(i=1;i<=n+m;i++)
			for(j=1;j<=n+m;j++)
				scanf("%d",&map[i][j]);
			for(k=1;k<=n+m;k++)
			{
				for(i=1;i<=n+m;i++)
				{
					if(map[i][k]==0)continue;//0表示不連通
					for(j=1;j<=n+m;j++)
					{
						if(map[k][j]==0||i==j)continue;
						if(map[i][j]==0||map[i][j]>map[i][k]+map[k][j])
							map[i][j]=map[i][k]+map[k][j];
						if(right<map[i][j])
							right=map[i][j];
					}
				}
			}
			while(left<right)
			{
				mid=(left+right)/2;
				makemap(mid);
				int sum=isap();
				if(sum==m)
					right=mid;
				else left=mid+1;
			}
			printf("%d\n",right);
	}
	return 0;
}