POJ 2112 Optimal Milking

这题我读懂题意后,蒙了,没思路,有思路也是不可行的。。。

果断看解题报告……都是二分+floy+最大流;写的很简单,看不懂;于是看代码!一看更蒙了!

怎么用二分的方法,试着去找ans呢?感觉挺无语的!

二分+最短路+最大流:先用floy求出各个奶牛到各个挤奶器的最短距离(或者说求出各个挤奶器到各个奶牛的最短距离)显然,这个是必须的,因为题中给的距离不一定是最短的!然后再用二分的方法去找答案,即在0~max(max为奶牛到挤奶器可能的最大距离,我认为是200*200=40000)用二分查找的方法去找最大距离的最小值;不断用mid的值去建网络流图添加源点0,汇点n+1,源点到所有挤奶器的距离为m即newmap[0][1..k]=m;奶牛到汇点的距离为1即newmap[k+1...n][n+1]=1;当map[挤奶器][奶牛]的距离<=mid时,建立边newmap[挤奶器][奶牛]=1;其它的边都初始化为0;然后求出maxflow,判断maxflow是否等于c;若等于令high=mid;若不等于令low=mid+1;最后low将会等于high就是最终的结果。概括地说一下:当用值mid去建网络图时,则保证了所有奶牛和挤奶器的距离的最大值为mid,就是试着看当它们的最大距离为mid时,是否满足所有的牛都可以挤奶(^_^),这个最大流嘛,很强大,没法子解释-----只可意会不可言传!

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

#define N 232
#define MAXVAL 40000

int map1[N][N],map2[N][N];
int k,c,m,n;

int getData()
{
int i,j;

if(EOF==scanf("%d %d %d",&k,&c,&m)) return 0;//改为EOF仍是WA,看来不是EOF的问题
n=k+c;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
scanf("%d",map1[i]+j);
if(i!=j && 0==map1[i][j]) map1[i][j]=MAXVAL;
}
}

return 1;
}

void floyd()
{
int i,j,k;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
if(MAXVAL!=map1[i][k])
for(j=1;j<=n;j++)
if(map1[i][k]+map1[k][j]<map1[i][j])
map1[i][j]=map1[i][k]+map1[k][j];
}

void buildGraph(int val)
{
int i,j;

memset(map2,0,sizeof(map2));
for(i=1;i<=k;i++) map2[0][i]=m;
for(i=k+1;i<=n;i++) map2[i][n+1]=1;

for(i=1;i<=k;i++)
for(j=k+1;j<=n;j++)
if(map1[i][j]<=val) //map2[i][j]=map2[j][i]=1;//终于发现这里map[j][i]=1错了!!
map2[i][j]=1;
}

int queue[N],font,rear,pre[N];
int Edmonds_Karp()
{
int v,u,minflow,maxflow=0;

while(1)
{
memset(pre,-1,sizeof(pre)); pre[0]=0;
font=rear=-1; queue[++rear]=0;

while(font<rear)
{
v=queue[++font];
for(u=1;u<=n+1;u++)
{
if(map2[v][u] && -1==pre[u])
pre[u]=v,queue[++rear]=u;
}
if(-1!=pre[n+1]) break;
}
if(-1==pre[n+1]) break;

minflow=MAXVAL;
// for(u=pre[n+1];u;u=pre[u])//发现错误:调试① u=pre[n+1],那么汇点和前一个点没更新
for(u=n+1;u;u=pre[u])
if(minflow>map2[pre[u]][u]) minflow=map2[pre[u]][u];

for(u=n+1;u;u=pre[u])
map2[pre[u]][u]-=minflow,map2[u][pre[u]]+=minflow;

maxflow+=minflow;
}

return maxflow;
}

void binarySearch()
{
int low=0,high=MAXVAL,mid;

while(low<high)
{
mid=(low+high)>>1;
buildGraph(mid);

if(c==Edmonds_Karp())
high=mid;
else low=mid+1;
}

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

void preprocessing()
{
floyd();
}

void solve()
{
while(getData())
{
preprocessing();
binarySearch();
}

}

int main()
{
//reopen("input.txt","r",stdin);

solve();

return 0;
}

588k 350ms

传说中还有一种方法:

二分+最短路+二分多重匹配

其实这个方法上一个更容易理解呵,用mid的去建二分图,看看是否能够匹配成功!

二分匹配是1:1,二分多重匹配是1:m(m:1);

二分多重匹配也可以通过“拆点”的方法即1:m,可以把1拆成m点就成了1:1,就可以用二分匹配做了

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

#define N 232
#define MAXVAL 40000

int map[N][N];//map2[N][N];
int k,c,m,n;

int getData()
{
int i,j;

if(EOF==scanf("%d %d %d",&k,&c,&m)) return 0;//改为EOF仍是WA,看来不是EOF的问题
n=k+c;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
scanf("%d",map[i]+j);
if(i!=j && 0==map[i][j]) map[i][j]=MAXVAL;
}
}

return 1;
}

void floyd()
{
int i,j,k;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
if(MAXVAL!=map[i][k])
for(j=1;j<=n;j++)
if(map[i][k]+map[k][j]<map[i][j])
map[i][j]=map[i][k]+map[k][j];
}

//int nodevp[202];//发现错误:这里的nodevp数组大小202,可能会小!
int nodevp[232];//应为232,因为奶牛的编号是从k+1开始到n,这样一改AC了!!
int nodeu[6000],next[6000],ind;
int machine[32][15],cnt[32];
int flag[32];

void addedge(int v,int u)
{
nodeu[ind]=u;
next[ind]=nodevp[v];
nodevp[v]=ind++;
}

void buildGraph(int val)
{
int i,j;

memset(nodevp,-1,sizeof(nodevp)); ind=0;

for(i=1;i<=k;i++)
for(j=k+1;j<=n;j++)
if(map[i][j]<=val)
addedge(j,i);
}

int DFS(int v)
{
int i,j,u;
for(i=nodevp[v];~i;i=next[i])
{
u=nodeu[i];
if(flag[u]) continue;
flag[u]=1;
if(cnt[u]<m)
{
machine[u][cnt[u]++]=v;
return 1;
}
for(j=0;j<m;j++)
{
if(DFS(machine[u][j]))
{
machine[u][j]=v;
return 1;
}
}
}

return 0;
}
int match()
{
int v;

memset(cnt,0,sizeof(cnt));

for(v=k+1;v<=n;v++)
{
memset(flag,0,sizeof(flag));
if(!DFS(v)) return 0;
}

return 1;
}


void binarySearch()
{
int low=0,high=MAXVAL,mid;

while(low<high)
{
mid=(low+high)>>1;
buildGraph(mid);

if(match()) high=mid;
else low=mid+1;
}

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

void preprocessing()
{
floyd();
}

void solve()
{
while(getData())
{
preprocessing();
binarySearch();
}

}

int main()
{
// freopen("input.txt","r",stdin);

solve();

return 0;
}

424k 63ms (⊙o⊙)…这么快额!

你可能感兴趣的:(poj)