0
点赞
收藏
分享

微信扫一扫

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\n" ,Ans);

}

return 0;

}






举报

相关推荐

0 条评论