poj 2112 floyd+最大流(所有牛挤奶走的最长路的最小值)

来源:互联网 发布:mac官网唇膏体验装 编辑:程序博客网 时间:2024/04/30 21:25

题意:给定K台挤奶机器和C头牛,每台挤奶机只能供M头牛挤奶。现在给出(K + C)*(K + C)的距离矩阵,表示第i个物体到第j个物体之间的路径长度,若此值为零,则说明其间不可直接到达。问怎么安排这C头牛到K台机器挤奶,使得需要走最长路程到挤奶机器的奶牛所走的路程最少,并求出这个最小值。

思路:首先利用Floyd算法求出每个奶牛到每个挤奶机的最短距离。

此后二分答案,先假定一个最大距离的的最小值 maxdist, 对每个maxdist值,都重新构图。 构图策略是:每个奶牛和挤奶器都是一个节点,添加一个源,连边到所有奶牛节点,这些边容量都是1。添加一个汇点,每个挤奶器都连边到它。这些边的容量都是M。如果奶牛节点i和挤奶器节点j之间的距离<= maxdist,则从i节点连一条边到j节点,表示奶牛i可以到挤奶器j去挤奶。该边容量为1。该图上的最大流如果是C(奶牛数),那么就说明假设的 maxdist成立,则减小 maxdist再试。

注意二分过程,设下界为low,上界为high。当最大流等于奶牛数量时,如果maxdist值等于low则返回答案,否则是high=maxdist(传统的二分查找是high=mid-1,这里相当于等于mid,不减一);当最大流小于奶牛数量时,使low=maxdist+1。

版本2用邻接表建图,且最大流算法的队列用stl实现。

内容部分参考北大郭炜老师的课件.

#include <stdio.h>#include <string.h>#define min(a,b) a<b?a:b#define max(a,b) a>b?a:b#define N 235int n,m,thresh;int dis[N][N],c[N][N],a[N],p[N],q[200000];void createmap(int res){int i,j;memset(c,0,sizeof(c));for(i = 1;i<=m;i++)//源点到牛c[0][i] = 1;for(i = m+1;i<=n+m;i++)//机器到汇点c[i][n+m+1] = thresh;for(i = 0;i<n;i++)//牛到机器for(j = n;j<n+m;j++)if(dis[i][j] <= res)c[j-n+1][i+m+1] = 1;}int maxflow(int s,int t){//最大流int front,rear,i,res=0;while(1){front = rear = -1;memset(a,0,sizeof(a));memset(p,0,sizeof(p));a[s] = 0x3fffffff;q[++rear] = s;while(front < rear){int now = q[++front];for(i = 0;i<=t;i++)if(!a[i] && c[now][i]>0){a[i] = min(a[now],c[now][i]);p[i] = now;q[++rear] = i;}}if(!a[t])break;res += a[t];for(i = t;i!=s;i=p[i]){c[p[i]][i] -= a[t];c[i][p[i]] += a[t];}}return res;}int main(){freopen("a.txt","r",stdin);while(scanf("%d %d %d",&n,&m,&thresh)!=EOF){int i,j,k,res,high=0,low=0;for(i = 0;i<n+m;i++)for(j = 0;j<n+m;j++){scanf("%d",&dis[i][j]);if(dis[i][j] == 0)dis[i][j] = 0x3fffffff;}//floydfor(k = 0;k<n+m;k++)for(i = 0;i<n+m;i++)for(j = 0;j<n+m;j++)dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j]);//确定二分上界highfor(i = 0;i<n;i++)for(j = n;j<n+m;j++)high = max(high,dis[i][j]);//二分答案while(low <= high){res = (low+high)/2;createmap(res);//每次都得重新建图if(m == maxflow(0,n+m+1)){if(res == low)break;high = res;//这是与传统二分查找不一样的地方}elselow = res+1;}printf("%d\n",res);}return 0;}

版本2:

#include <cstdio>#include <cstring>#include <algorithm>#include <map>#include <queue>#include <cstdlib>using namespace std;#define INF 0x3fffffff#define clc(s,t) memset(s,t,sizeof(s))#define N 235int m,c,n,k;int dis[N][N];struct edge{    int y,next,c;}e[N*N*2];int first[N],top;void addedge(int x,int y,int c){    e[top].y = y;    e[top].c = c;    e[top].next = first[x];    first[x] = top++;}void add(int x,int y,int c){    addedge(x,y,c);    addedge(y,x,0);}void create(int d){    int i,j;    clc(first,-1);    top = 0;    for(i = 1;i<=m;i++)        add(0,i,k);    for(i = m+1;i<=m+c;i++)        add(i,n+1,1);    for(i = 1;i<=m;i++)        for(j = m+1;j<=m+c;j++)            if(dis[i][j] <= d)                add(i,j,1);}int maxflow(){    queue<int> q;    int i,now,res=0,p[N],a[N],id[N];    while(1){        clc(p,0);        clc(a,0);        a[0] = INF;        q.push(0);        while(!q.empty()){            now = q.front();            q.pop();            for(i = first[now];i!=-1;i=e[i].next){                if(!a[e[i].y] && e[i].c>0){                    a[e[i].y] = min(a[now],e[i].c);                    p[e[i].y] = now;                    id[e[i].y] = i;                    q.push(e[i].y);                }            }        }        if(a[n+1] == 0)            break;        res+=a[n+1];        for(i = n+1;i!=0;i=p[i]){            e[id[i]].c -= a[n+1];            e[id[i]^1].c += a[n+1];        }    }    return res;}int main(){    while(scanf("%d %d %d",&m,&c,&k)!=EOF){        int i,j,w,low,high,mid;        n = m+c;        high = 0;        for(i = 1;i<=n;i++)            for(j = 1;j<=n;j++){                scanf("%d",&dis[i][j]);                if(i!=j && dis[i][j] == 0)                    dis[i][j] = INF;            }        for(w = 1;w<=n;w++)            for(i = 1;i<=n;i++)                for(j = 1;j<=n;j++)                    dis[i][j] = min(dis[i][j],dis[i][w]+dis[w][j]);        high = 46000;        low = 0;        while(low < high){            mid = (low+high)>>1;            create(mid);            if(maxflow() == c)                high = mid;            else                low = mid+1;        }        printf("%d\n",low);    }    return 0;}


0 0