POJ 2112:floyd+网络流+二分

一开始以为是费用流。。半天搞不出

经过学弟讲解才知道是这么个问题

先用floyd求出任意两个事物间的最短距离,题目要求在所有牛都能找到机器的前提下,最长距离最小(其实看到这样的字眼就应该想到二分),我们可以二分答案

对于每一个答案建图跑网络流,只建容量小于mid的边,看看是否所有的牛都能找到机器就好

不知道为何用sap模板老是TLE - -||明明感觉比dinic要快啊..

 

#include"cstdio"
#include"queue"
#include"cmath"
#include"stack"
#include"iostream"
#include"algorithm"
#include"cstring"
#include"queue"
#include"map"
#include"set"
#include"vector"
#define ll long long
#define mems(a,b) memset(a,b,sizeof(a))

using namespace std;
const int MAXN = 350;
const int MAXE = 20050;
const int INF = 0x3f3f3f3f;
struct node{
    int s,e,next,val;
    node(){}
    node(int a,int b,int c,int d):s(a),e(b),next(c),val(d){}
}edge[MAXE];
int tot,src,des,m,k,c;
int first[MAXN],dep[MAXN],gap[MAXN];
int mat[MAXN][MAXN];

void init(){
    tot=0;
    mems(first,-1);
}

void addedge(int u,int v,int w){
    //cout<<u<<'\t'<<v<<'\t'<<w<<endl;
    edge[tot]=node(u,v,first[u],w);
    first[u]=tot++;
    edge[tot]=node(v,u,first[v],0);
    first[v]=tot++;
}



bool bfs(int src,int des){
    mems(dep,-1);
    queue<int> q;
    while(!q.empty()) q.pop();
    q.push(src);
    dep[src]=0;
    while(!q.empty()){
        int cur=q.front();q.pop();
        for(int i=first[cur];i!=-1;i=edge[i].next){
            int v=edge[i].e;
            if(dep[v]!=-1||edge[i].val<=0) continue;
            dep[v]=dep[cur]+1;
            q.push(v);
        }
    }
    return dep[des]!=-1;
}

int dfs(int s,int t,int flow){
    if(s==t) return flow;
    int newflow=0;
    for(int i=first[s];i!=-1;i=edge[i].next){
        int v=edge[i].e;
        int w=edge[i].val;
        if(dep[v]!=dep[s]+1||!edge[i].val)
            continue;
        int temp=dfs(v,t,min(w,flow-newflow));
        newflow+=temp;
        edge[i].val-=temp;
        edge[i^1].val+=temp;
        if(newflow==flow) break;
    }
    return newflow;
}

bool dinic(int s,int t,int c){
    int sum=0;
    while(bfs(s,t)){
        sum+=dfs(s,t,INF);
    }
    return sum==c;
}

void build(int maxv){
    init();
    for(int i=1;i<=k;i++) addedge(src,i,m);
    for(int i=k+1;i<=k+c;i++) addedge(i,des,1);

    for(int i=1;i<=k;i++)
    for(int j=k+1;j<=k+c;j++) if(mat[i][j]<=maxv) addedge(i,j,1);
}

void floyd(int N){
    for(int k=1;k<=N;k++)
    for(int i=1;i<=N;i++)
    for(int j=1;j<=N;j++) mat[i][j]=min(mat[i][j],mat[i][k]+mat[k][j]);
}

int main(){
    //freopen("in.txt","r",stdin);
    while(~scanf("%d%d%d",&k,&c,&m)){
        for(int i=1;i<=k+c;i++)
        for(int j=1;j<=k+c;j++){
            scanf("%d",&mat[i][j]);
            if(!mat[i][j]) mat[i][j]=INF;
        }
        floyd(k+c);
        src=0;
        des=k+c+1;

        int low=0,high=INF,mid;
        int ans=INF;
        while(low<=high){
            int mid=(low+high)>>1;
            build(mid);
            if(dinic(src,des,c)){
                ans=min(ans,mid);
                high=mid-1;
            }
            else low=mid+1;
        }
        cout<<ans<<endl;
    }
    return 0;
}

 

posted @ 2016-01-20 20:53  Septher  阅读(177)  评论(0编辑  收藏  举报