雕刻时光

just do it……nothing impossible
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

二分查找+网络流——poj 2112

Posted on 2012-03-21 22:36  huhuuu  阅读(336)  评论(0编辑  收藏  举报

先 folyd 求出任意两点可以到达的距离,

由于我们不知道最短距离为多少,所以用二分查找来逼近答案

接着构建容量网络:

增加 源点 (n+1),设置源点到牛的容量为1  (一开始以为是INF,显然是错的)

增加 汇点 (0),设置汇点到机器的容量为 M

在通过二分出来的那个答案,统计牛到机器的容量

 

最后网络流最大流,继续二分,直到最佳答案

View Code
#include<stdio.h>
#include<string.h>

const int inf=100000000;
const int MAXN=309;
int map[MAXN][MAXN];
int dis[MAXN][MAXN];
int flow[MAXN][MAXN];
int K,C,M;

int min(int a,int b)
{
if(a<b)return a;
else return b;
}

int max_flow(int n,int mat[][MAXN],int source,int sink)
{
int v[MAXN],c[MAXN],p[MAXN],ret=0,i,j;
for(;;){
for(i=0;i<n;i++)
v[i]=c[i]=0;
for(c[source]=inf;;){
for(j=-1,i=0;i<n;i++)
if(!v[i]&&c[i]&&(j==-1||c[i]>c[j]))
j=i;
if(j<0)return ret;
if(j==sink)break;
for(v[j]=1,i=0;i<n;i++)
if(mat[j][i]>c[i]&&c[j]>c[i])
c[i]=mat[j][i]<c[j]?mat[j][i]:c[j],p[i]=j;
}
for(ret+=j=c[i=sink];i!=source;i=p[i])
mat[p[i]][i]-=j,mat[i][p[i]]+=j;
}
return ret;
}

void build(int max)
{
int i,j,k;
memset(map,0,sizeof(map));

for(i=1;i<=K;i++)
{
map[i][0]=M;
}
for(i=K+1;i<=n;i++)
{
map[n+1][i]=1;//一开始赋值为inf,事实上一头牛就只有一个单位容量
}

int n=K+C;
for(i=K+1;i<=n;i++)
{
for(j=1;j<=K;j++)
{
if(dis[i][j]<=max)
map[i][j]=1;
}
}


}

int main()
{
int n;
while(scanf("%d%d%d",&K,&C,&M)!=EOF)
{
n=K+C;
int i,j,k;

memset(map,0,sizeof(map));
memset(dis,0,sizeof(dis));

int mmax=0;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
scanf("%d",&dis[i][j]);
if(dis[i][j]==0)dis[i][j]=inf;
}
}

for(k=1;k<=n;k++)
{
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}

for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(mmax<dis[i][j])
{
mmax=dis[i][j];
}
}
}


int l=0,r=mmax,mid;

int min=inf;

while(l<=r)
{
mid=(l+r)>>1;
build(mid);
int flow=max_flow(n+2,map,n+1,0);
if(flow>=C) r=mid-1;
else l=mid+1;

if(flow>=C)
{
if(mid<min)
min=mid;
}
}

printf("%d\n",min);
}

return 0;
}