POJ1149 最大流经典建图PIG
生活随笔
收集整理的這篇文章主要介紹了
POJ1149 最大流经典建图PIG
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題意:
? ? ? 有一個人,他有m個豬圈,每個豬圈里都有一定數量的豬,但是他沒有鑰匙,然后依次來了n個顧客,每個顧客都有一些鑰匙,還有他要賣豬的數量,每個顧客來的時候主人用顧客的鑰匙打開相應的門,可以調整豬的數量,然后賣給一些豬給這個顧客(賣多少自己決定),顧客走之后所有的們就都鎖上了,問主人最多能買多少頭豬。
思路:
? ? ? 經典的建圖,這已經是我第三次做這個題目了,大一,大二,大三每年做流的時候都會想到它,然后回來做一次,沒辦法,感覺比較經典,雖然現在做著直接1A沒有第一次做的時候千辛萬苦ac那么成就感了,但是經典就是經典,大體說下思路吧,這個題解寫了好多次了,題目中說來了一個顧客之后可以調整數量,那么我們直接就把這個顧客所有能打開的豬圈變成一個豬圈,用虛擬出來的一個點代替,以后無論誰在來,只要訪問這其中的某個豬圈就用他當前虛擬的點來代表他,可以開一個數組映射每個豬圈當前虛擬的點,虛擬的點可以再被虛擬,就像OS一樣,可以一層一層的虛擬,我的建圖是這樣(可以倒過來,或者是用別的姿勢,怎么都行,寫著順手,思路清晰就行):
(1) s 向所有的顧客連接一條邊 流量是顧客要買的豬的數量
(2) 所有的豬圈向t連接一條邊,流量是豬圈的豬的數量
(3) 對于每一個顧客,我們首先虛擬出來一個點,然后把這個顧客所有連接的點都指向這個 ? ?虛擬的點,比如當前的這個顧客有三把鑰匙1,2,3,因為這三個豬圈可以直接調整數量 ? ?了,所以我們可以讓虛擬出來的這個點a代替當前這步的三個點,1->a ,2->a ,3->a,然 ? ?后在更新上面說的那個hash[],hash[1] = a ,hash[2] = a ,hash[3] = a,以后只要是 ? ?訪問1,2,3中的任何一個,直接訪問a,就行了,然后在建立一條當前顧客到新虛擬出來 ? ? 的這個點的邊,流量INF。
ok,就是以上那些,要是不明白可以自己按照上面的見圖思路畫個圖,很容易理解。
#include<queue>
#include<stdio.h>
#include<string.h>
#define N_node 1500
#define N_edge 100000
#define INF 1000000000
using namespace std;
typedef struct
{
? ? int to ,cost ,next;
}STAR;
typedef struct
{
? ? int x ,t;
}DEP;
STAR E[N_edge];
DEP xin ,tou;
int list[N_node] ,listt[N_node] ,tot;
int deep[N_node] ,hash[N_node];
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;
}
bool BFS_DEEP(int s ,int t ,int n)
{
? ? memset(deep ,255 ,sizeof(deep));
? ? xin.x = s ,xin.t = 0;
? ? queue<DEP>q;
? ? q.push(xin);
? ? deep[s] = 0;
? ? 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 minn(int x ,int y)
{
? ? return x < y ? x : y;
}
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 c = E[k].cost;
? ? ? ? int to = E[k].to;
? ? ? ? if(!c || deep[to] != deep[s] + 1)
? ? ? ? continue;
? ? ? ? int tmp = DFS_Flow(to ,t ,minn(c ,flow - nowflow));
? ? ? ? nowflow += tmp;
? ? ? ? E[k].cost -= tmp;
? ? ? ? E[k^1].cost += tmp;
? ? ? ? if(nowflow == flow) 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;
}
int main ()
{
? ? int n ,m ,i ,q ,a;
? ? while(~scanf("%d %d" ,&m ,&n))
? ? {
? ? ? ? memset(list ,0 ,sizeof(list));
? ? ? ? tot = 1;
? ? ? ? for(i = 1 ;i <= m ;i ++)
? ? ? ? {
? ? ? ? ? ? scanf("%d" ,&a);
? ? ? ? ? ? add(i + n ,m + n + n + 1 ,a);
? ? ? ? ? ? hash[i] = i + n;
? ? ? ? }
? ? ? ? for(i = 1 ;i <= n ;i ++)
? ? ? ? {
? ? ? ? ? ? scanf("%d" ,&q);
? ? ? ? ? ? while(q--)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? scanf("%d" ,&a);
? ? ? ? ? ? ? ? add(i + n + m ,hash[a] ,INF);
? ? ? ? ? ? ? ? hash[a] = i + n + m;
? ? ? ? ? ? }
? ? ? ? ? ? add(i ,i + n + m ,INF);
? ? ? ? ? ? scanf("%d" ,&a);
? ? ? ? ? ? add(0 ,i ,a);
? ? ? ? }
? ? ? ? printf("%d\n" ,DINIC(0 ,n + m + n + 1 ,n + m + n + 1));
? ? }
? ? return 0;
}
? ? ? 有一個人,他有m個豬圈,每個豬圈里都有一定數量的豬,但是他沒有鑰匙,然后依次來了n個顧客,每個顧客都有一些鑰匙,還有他要賣豬的數量,每個顧客來的時候主人用顧客的鑰匙打開相應的門,可以調整豬的數量,然后賣給一些豬給這個顧客(賣多少自己決定),顧客走之后所有的們就都鎖上了,問主人最多能買多少頭豬。
思路:
? ? ? 經典的建圖,這已經是我第三次做這個題目了,大一,大二,大三每年做流的時候都會想到它,然后回來做一次,沒辦法,感覺比較經典,雖然現在做著直接1A沒有第一次做的時候千辛萬苦ac那么成就感了,但是經典就是經典,大體說下思路吧,這個題解寫了好多次了,題目中說來了一個顧客之后可以調整數量,那么我們直接就把這個顧客所有能打開的豬圈變成一個豬圈,用虛擬出來的一個點代替,以后無論誰在來,只要訪問這其中的某個豬圈就用他當前虛擬的點來代表他,可以開一個數組映射每個豬圈當前虛擬的點,虛擬的點可以再被虛擬,就像OS一樣,可以一層一層的虛擬,我的建圖是這樣(可以倒過來,或者是用別的姿勢,怎么都行,寫著順手,思路清晰就行):
(1) s 向所有的顧客連接一條邊 流量是顧客要買的豬的數量
(2) 所有的豬圈向t連接一條邊,流量是豬圈的豬的數量
(3) 對于每一個顧客,我們首先虛擬出來一個點,然后把這個顧客所有連接的點都指向這個 ? ?虛擬的點,比如當前的這個顧客有三把鑰匙1,2,3,因為這三個豬圈可以直接調整數量 ? ?了,所以我們可以讓虛擬出來的這個點a代替當前這步的三個點,1->a ,2->a ,3->a,然 ? ?后在更新上面說的那個hash[],hash[1] = a ,hash[2] = a ,hash[3] = a,以后只要是 ? ?訪問1,2,3中的任何一個,直接訪問a,就行了,然后在建立一條當前顧客到新虛擬出來 ? ? 的這個點的邊,流量INF。
ok,就是以上那些,要是不明白可以自己按照上面的見圖思路畫個圖,很容易理解。
#include<queue>
#include<stdio.h>
#include<string.h>
#define N_node 1500
#define N_edge 100000
#define INF 1000000000
using namespace std;
typedef struct
{
? ? int to ,cost ,next;
}STAR;
typedef struct
{
? ? int x ,t;
}DEP;
STAR E[N_edge];
DEP xin ,tou;
int list[N_node] ,listt[N_node] ,tot;
int deep[N_node] ,hash[N_node];
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;
}
bool BFS_DEEP(int s ,int t ,int n)
{
? ? memset(deep ,255 ,sizeof(deep));
? ? xin.x = s ,xin.t = 0;
? ? queue<DEP>q;
? ? q.push(xin);
? ? deep[s] = 0;
? ? 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 minn(int x ,int y)
{
? ? return x < y ? x : y;
}
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 c = E[k].cost;
? ? ? ? int to = E[k].to;
? ? ? ? if(!c || deep[to] != deep[s] + 1)
? ? ? ? continue;
? ? ? ? int tmp = DFS_Flow(to ,t ,minn(c ,flow - nowflow));
? ? ? ? nowflow += tmp;
? ? ? ? E[k].cost -= tmp;
? ? ? ? E[k^1].cost += tmp;
? ? ? ? if(nowflow == flow) 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;
}
int main ()
{
? ? int n ,m ,i ,q ,a;
? ? while(~scanf("%d %d" ,&m ,&n))
? ? {
? ? ? ? memset(list ,0 ,sizeof(list));
? ? ? ? tot = 1;
? ? ? ? for(i = 1 ;i <= m ;i ++)
? ? ? ? {
? ? ? ? ? ? scanf("%d" ,&a);
? ? ? ? ? ? add(i + n ,m + n + n + 1 ,a);
? ? ? ? ? ? hash[i] = i + n;
? ? ? ? }
? ? ? ? for(i = 1 ;i <= n ;i ++)
? ? ? ? {
? ? ? ? ? ? scanf("%d" ,&q);
? ? ? ? ? ? while(q--)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? scanf("%d" ,&a);
? ? ? ? ? ? ? ? add(i + n + m ,hash[a] ,INF);
? ? ? ? ? ? ? ? hash[a] = i + n + m;
? ? ? ? ? ? }
? ? ? ? ? ? add(i ,i + n + m ,INF);
? ? ? ? ? ? scanf("%d" ,&a);
? ? ? ? ? ? add(0 ,i ,a);
? ? ? ? }
? ? ? ? printf("%d\n" ,DINIC(0 ,n + m + n + 1 ,n + m + n + 1));
? ? }
? ? return 0;
}
總結
以上是生活随笔為你收集整理的POJ1149 最大流经典建图PIG的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: POJ3322滚箱子游戏(不错)
- 下一篇: hdu3374最小表示法+KMP