POJ2391 Floyd+离散化+二分+DINIC

题意:
      有n个猪圈,每个猪圈里面都有一定数量的猪(可能大于当前猪圈的数量),每个猪圈都有自己的容量,猪圈与猪圈之间给出了距离,然后突然下雨了,问多久之后所有的猪都能进圈。


思路:
       先跑一遍Floyd求出任意两点之间的最短距离,对于时间,也就是答案,我们可以二分去找,然后对于每次二分,我们可以用DINIC去判断是否满足要求,建图的时候记得拆点,一开始我感觉不用抄点,但是都敲完了,发现不行,又重新建图了,拆成二分图,然后根据当前二分的值连边。。。这个题比较简单,没啥难点,就是长时间没写了,练练手,还有提醒一点,二分的时候可以不直接二分时间,我们可以吧所有可能的时间都找出来,排序,离散化一下,这样直接二分下标,减少时间开销(直接不离散化目测也行,但是离散化能更快点)。下面是我的代码,用的方法是 Floyd+离散化+二分+DINIC做的,这个题思路不难,就是练练手,就解释这么多。
      


#include<queue>
#include<stdio.h>
#include<string.h>
#include<algorithm>


#define N_node 400 + 10
#define N_edge (200 * 200 + 400) * 2 + 100
#define INF 2000000000
#define III 0x3f3f3f3f3f3f3f3f




using namespace std;


typedef struct
{
    int to ,cost ,next;
}STAR;


typedef struct
{
    int x ,t;
}DEP;


DEP xin ,tou;
STAR E[N_edge];
int list[N_node] ,listt[N_node] ,tot;
int deep[N_node];
long long map[202][202];
long long tmp[50000] ,num[50000];
int L[202] ,R[202];
int S;


void add(int a ,int b ,int c)
{
    E[++tot].to = b;
    E[tot].cost = c;
    E[tot].next = list[a];
    list[a] = tot;


    E[++tot].to = a;
    E[tot].cost = 0;
    E[tot].next = list[b];
    list[b] = tot;
}


int minn(int x ,int y)
{
    return x < y ? x : y;
}


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 ++)
    if(map[i][j] > map[i][k] + map[k][j])
    map[i][j] = map[i][k] + map[k][j];
}


bool BFS_Deep(int s ,int t ,int n)
{
    memset(deep ,255 ,sizeof(deep));
    deep[s] = 0;
    xin.x = s ,xin.t = 0;
    queue<DEP>q;
    q.push(xin);
    while(!q.empty())
    {
        tou = q.front();
        q.pop();
        for(int k = list[tou.x] ;k ;k = E[k].next)
        {
            xin.x = E[k].to;
            xin.t = tou.t + 1;
            if(deep[xin.x] != -1 || !E[k].cost)
            continue;
            deep[xin.x] = xin.t;
            q.push(xin);
        }
    }
    for(int i = 0 ;i <= n ;i ++)
    listt[i] = list[i];
    return deep[t] != -1;
}


int DFS_Flow(int s ,int t ,int flow)
{
    if(s == t) return flow;
    int nowflow = 0;
    for(int k = listt[s] ;k ;k = E[k].next)
    {
        listt[s] = k;
        int to = E[k].to;
        int c = E[k].cost;
        if(deep[to] != deep[s] + 1 || !c)
        continue;
        int tmp = DFS_Flow(to ,t ,minn(c ,flow - nowflow));
        nowflow += tmp;
        E[k].cost -= tmp;
        E[k^1].cost += tmp;
        if(flow == nowflow) break;
    }
    if(!nowflow) deep[s] = 0;
    return nowflow;
}


int DINIC(int s ,int t ,int n)
{
    int Ans = 0;
    while(BFS_Deep(s ,t ,n))
    {
        Ans += DFS_Flow(s ,t ,INF);
    }
    return Ans;
}


void Buid(int n ,long long mid)
{
    memset(list ,0 ,sizeof(list)) ,tot = 1;
    for(int i = 1 ;i <= n ;i ++)
    add(0 ,i ,L[i]) ,add(i + n ,n + n + 1 ,R[i]);
    for(int i = 1 ;i <= n ;i ++)
    for(int j = 1 ;j <= n ;j ++)
    if(map[i][j] <= mid) add(i ,j + n ,INF);
}


long long solve(int n)
{
    int t = 0;
    for(int i = 1 ;i <= n ;i ++)
    for(int j = i ;j <= n ;j ++)
    if(map[i][j] != III) tmp[++t] = map[i][j];
    sort(tmp + 1 ,tmp + t + 1);
    int numn = 0;
    for(int i = 1 ;i <= t ;i ++)
    if(i == 1 || tmp[i] != tmp[i-1])
    num[++numn] = tmp[i];
    int low = 1 ,up = numn ,mid;
    long long Ans = -1;
    while(low <= up)
    {
        mid = (low + up) >> 1;
        Buid(n ,num[mid]);
        if(DINIC(0 ,n + n + 1 ,n + n + 1) == S)
        {
            Ans = num[mid];
            up = mid - 1;
        }else low = mid + 1;
    }
    return Ans;
}


int main ()
{
    int n ,m ,i ,j;
    long long a ,b ,c;
    while(~scanf("%d %d" ,&n ,&m))
    {
        for(S = 0 ,i = 1 ;i <= n ;i ++)
        {
            scanf("%d %d" ,&L[i] ,&R[i]);
            S += L[i];
        }
        for(i = 1 ;i <= n ;i ++)
        {
            for(j = i + 1;j <= n ;j ++)
            map[i][j] = map[j][i] = III;
            map[i][i] = 0;
        }


        for(i = 1 ;i <= m ;i ++)
        {
            scanf("%lld %lld %lld" ,&a ,&b ,&c);
            if(map[a][b] > c) map[a][b] = map[b][a] = c;
        }
        Floyd(n);
        long long Ans = solve(n);
        printf("%lld " ,Ans);
    }
    return 0;
}





原文地址:https://www.cnblogs.com/csnd/p/12062470.html