POJ 2112 /// 最大流+floyd+二分

题目大意:

有 k台挤奶机 和 c头奶牛

每台挤奶机最多为m头奶牛服务

给定所有挤奶机和奶牛两两之间的距离

求一种分配 使得 奶牛与挤奶机之间的最远距离 最小化

 

floyd求得所有挤奶机与奶牛两两之间的最短距离

二分一个最远距离M 建图

超级源点s与所有奶牛连容量为1的边

所有挤奶机与超级汇点t连容量为m的边

奶牛与挤奶机之间距离<=M的连容量为1的边

跑s到t的最大流 若最大流为c 说明这个最远距离M是符合要求的

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define LL long long 
#define INF 0x3f3f3f3f
#define mem(i,j) memset(i,j,sizeof(i))
const int N=300;
int d[N][N],L,R;
int n,m,s,t;

/**Dinic*/
struct NODE { int v,w,r; };
vector <NODE> E[N];
void addE(int u,int v,int w) {
    E[u].push_back({v,w,E[v].size()});
    E[v].push_back({u,0,E[u].size()-1});
}
int lev[N], cur[N];
bool bfs(int s,int t) {
    mem(lev,0); lev[s]=1; 
    queue <int> q; q.push(s);
    while(!q.empty()) {
        int u=q.front(); q.pop();
        for(int i=0;i<E[u].size();i++) {
            NODE e=E[u][i];
            if(e.w>0 && !lev[e.v]) {
                lev[e.v]=lev[u]+1;
                q.push(e.v);
            }
        }
    }
    return lev[t]>0;
}
int dfs(int s,int t,int f) {
    if(s==t) return f;
    for(int& i=cur[s];i<E[s].size();i++) {
        NODE& e=E[s][i];
        if(e.w>0 && lev[s]<lev[e.v]) {
            int d=dfs(e.v,t,min(f,e.w));
            if(d>0) {
                e.w-=d; E[e.v][e.r].w+=d;
                return d;
            }
        }
    }
    return 0;
}
int maxFlow(int s,int t) {
    int flow=0, f;
    while(bfs(s,t)) {
        mem(cur,0);
        while((f=dfs(s,t,INF))>0) flow+=f;
    }
    return flow;
}
/***/

bool check(int k,int c,int m,int M) {
    for(int i=0;i<=n+1;i++) E[i].clear();
    s=0,t=n+1;
    for(int i=k+1;i<=n;i++) addE(s,i,1);
    for(int i=1;i<=k;i++) addE(i,t,m);
    for(int i=k+1;i<=n;i++)
        for(int j=1;j<=k;j++)
            if(d[i][j]<=M) addE(i,j,1);
    return maxFlow(s,t)==c;
}

void floyd(int k,int c) {
    L=INF, R=-INF;
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++) {
                d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
                L=min(L,d[i][j]); R=max(R,d[i][j]);
            }
}

int main()
{
    int k,c,m; 
    while(~scanf("%d%d%d",&k,&c,&m)) { 
        n=k+c;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++) {
                scanf("%d",&d[i][j]);
                if(i!=j && !d[i][j])
                    d[i][j]=INF;
            } 
        floyd(k,c); 
        int ans=0;
        while(L<=R) {
            int M=(L+R)>>1;
            if(check(k,c,m,M)) 
                ans=M,R=M-1;
            else L=M+1;
        }
        printf("%d\n",ans); 
    }
    
    return 0;
}
View Code

 

posted @ 2019-04-07 01:38  _Jessie  阅读(143)  评论(0编辑  收藏  举报