POJ2391 Floyd+离散化+二分+DINIC
生活随笔
收集整理的這篇文章主要介紹了
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;
}
? ? ? 有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;
}
總結
以上是生活随笔為你收集整理的POJ2391 Floyd+离散化+二分+DINIC的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: POJ2195费用流+BFS建图
- 下一篇: POJ2431贪心(最少加油次数)