POJ2112解题报告【网络流-初级-isap+floyd_warshall+二分】

题目连接:http://poj.org/problem?id=2112

题意:有C头牛和K个挤奶机,每个挤奶机最多能为M头牛挤奶,他们在农场的不同位置。牛和牛、牛和机器之间可能有路,牛只能沿着路移动。给出路的长度,问要让这些牛都挤完奶,所有牛中走得最远的牛的行走路程最短是多少?

解题思路:首先要建图,把每个牛和挤奶机都看成节点,节点间的边既是他们之间的路的长度。然后用floyd算法,求出每个点之间的最短距离。记录最长的距离,然后二分该距离。再建一个网络流的图,图中包括一个源点、一个汇点、挤奶机的点、牛的点,源点和牛之间都连上容量为1的边,牛和挤奶机之间的距离如果小于mid(之前二分的距离),那么就建立一条容量为1的边,每个挤奶机和汇点之间都建立一条容量为K的边。然后ISAP算法求最大流,如果最大流等于C,向下二分否则向上二分。

算法:ISAP+floyd_walshall+二分

#include<cstdio>
#include<cstring>
#include<queue>
#include<stack>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<map>
#include<string>


//#define r(x,date) (*((STRUCT*)x).date)
//#define dp(i,j) dp[i][j]
//#define dp(i,j,k) dp[i][j][k]
#define INF 0x7ffffff
#define ff(i,from,to) for(i=from;i<=to;i++)
#define rff(i,from,to) for(i=from;i>=to;i--)
#define ll long long
#define MAX_SIDE 110000
#define MAX_NODE 300
#define mset(a,num) memset(a,num,sizeof(a))
using namespace std;

template<class T>bool myfun_upmax(T &a,const T&b){return b>a?a=b,1:0;}
template<class T>bool myfun_upmin(T &a,const T&b){return b<a?a=b,1:0;}
template<class T>void myfun_swap(T &a,T &b){T temp;temp=a;a=b;b=temp;}
template<class T>T myfun_max(const T a,const T b){return a>b?a:b;}
template<class T>T myfun_min(const T a,const T b){return a<b?a:b;}


int cmp(const void *a,const void *b){
    return 0;
}

inline void readint(int &ret) {
	char c;
	do {	c = getchar();
	} while(c < '0' || c > '9');
	ret = c - '0';
	while((c=getchar()) >= '0' && c <= '9')
		ret = ret * 10 + ( c - '0' );
}

int node[MAX_NODE];
struct SIDE{
    int to,next,c;
    SIDE(){}
    SIDE(int to,int next,int c):to(to),next(next),c(c){}
}side[MAX_SIDE];

int top;
void add_side(int u,int v,int c){
    side[top]=SIDE(v,node[u],c);
    node[u]=top++;
    side[top]=SIDE(u,node[v],0);
    node[v]=top++;
}

int START,END,SIZE;
int gap[MAX_NODE],pre[MAX_NODE],dis[MAX_NODE],cur[MAX_NODE];
int sap(){
    int maxflow=0;
    int aug=INF;
    int u=START,v;
    for(int i=0;i<SIZE;i++){
        gap[i]=dis[i]=0;
        cur[i]=node[i];
    }

    gap[START]=SIZE;
    pre[START]=START;
    while(dis[u]<SIZE){
        for(int &i=cur[u];i!=-1;i=side[i].next){
            v=side[i].to;
            if( side[i].c && dis[u]==dis[v]+1)break;
        }

        if(cur[u]!=-1){
            myfun_upmin(aug,side[cur[u]].c);
            pre[v]=u;u=v;
            if(u==END){
                maxflow+=aug;
                while(u!=START){
                    u=pre[u];
                    side[cur[u]].c-=aug;
                    side[cur[u]^1].c+=aug;
                }
                aug=INF;
            }
        }else{
            int min_dis=SIZE;
            for(int i=node[u];i!=-1;i=side[i].next){
                v=side[i].to;
                if(side[i].c && myfun_upmin(min_dis,dis[v]))
                    cur[u]=i;
            }
            if(--gap[dis[u]]==0)break;
            ++gap[dis[u]=min_dis+1];
            u=pre[u];
        }
    }
    return maxflow;
}

int K,C;
int N;
int matrix[MAX_NODE][MAX_NODE];
int floyd_warshall(){
    int MAX=0;
    for(int k=0;k<N;k++){
        for(int i=0;i<N;i++)
        for(int j=0;j<N;j++){
            if(i!=j && matrix[i][k]+matrix[k][j]<matrix[i][j]){
                matrix[i][j]=matrix[i][k]+matrix[k][j];
                if(matrix[i][j]<INF && matrix[i][j]>MAX)
                    MAX=matrix[i][j];
            }
        }
    }
    return MAX;
}

int M;
void build(int limit){
    //length not less than the limit
    top=0;
    for(int i=0;i<N+2;i++)node[i]=-1;
    for(int i=0;i<K;i++){
        for(int j=K;j<N;j++){
            if(matrix[i][j]<=limit)
                add_side(j,i,1);
        }
    }
    int i;
    for(i=0;i<K;i++){
        add_side(i,END,M);
    }
    for(;i<N;i++){
        add_side(START,i,1);
    }
}

int solve(int low,int high){
    while(low<=high){
        int mid=low+(high-low)/2;
        build(mid);
        int r=sap();
        if(r==C)high=mid-1;
        else low=mid+1;
    }
    return low;
}

int main()
{
    readint(K);
    readint(C);
    readint(M);
    N=K+C;
    START=N;
    END=N+1;
    SIZE=N+2;
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            readint(matrix[i][j]);
            if(matrix[i][j]==0)matrix[i][j]=INF;
        }
    }

    int max_path=floyd_warshall();
    int r=solve(1,max_path);
    printf("%d\n",r);
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值