1. 程式人生 > >[BZOJ1280]-Emmy賣豬pigs-網路流

[BZOJ1280]-Emmy賣豬pigs-網路流

說在前面

me終於要想到網路流了!!!然後耐心沒了…
然後就去看了題解
喵喵喵喵喵????


題目

BZOJ1280傳送門
看題可戳傳送門


解法

首先我們發現這是一個分配問題
分配問題一般有兩種解法,第一種是網路流,第二種是倒著dp(有時候分配問題倒過來就是需求問題,就可以用dp解決)
這個題me發現,正著/倒著都沒辦法轉化成需求問題。
然後me想,這個題的分配關係是有拓撲序的,應該可以建個圖跑跑
然後me就去看了題解

那麼對於這個題,我們可以建出一個比較顯然的網路流圖:
把每個人的購買操作看成時間軸,並把豬圈拆點
每個時間的豬圈 都向 下個時間的豬圈 連邊;人連匯點;源點連起始豬圈;當前人可購買的豬圈,向人連邊,人向下一個時間的這些豬圈連邊

然後我們發現這個圖,很多inf邊,於是我們考慮把沒有用的點全部去掉。最後就剩下了人和人連邊:對於第i個豬圈,上一個來這裡的人 向 下一個來這裡的人 連邊inf。如果是第一個來的,S向其連 豬圈大小 的邊

理解一下這個圖,相當於是 每個人 實際上就是一個「排程站」,下一個人如果需要,那麼這次開門的時候,就放一些pig進去給下一個人。不難發現這是正確的

(感覺這個建圖還蠻有意思的)


下面是程式碼

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace
std ; bool acce[105][105] ; int N , M , head[105] , tp = 1 , a[1005] , pre[1005] ; int S , T ; struct Path{ int pre , to , flow ; } p[22005] ; void In( int t1 , int t2 , int t3 ){ p[++tp] = ( Path ){ head[t1] , t2 , t3 } ; head[t1] = tp ; p[++tp] = ( Path ){ head[t2] , t1 , 0 } ; head[t2] = tp ; } int
que[105] , fr , ba , dis[105] ; bool BFS(){ memset( dis , -1 , sizeof( dis ) ) ; fr = 1 , que[ ba = 1 ] = S , dis[S] = 0 ; while( ba >= fr ){ int u = que[fr++] ; for( int i = head[u] ; i ; i = p[i].pre ){ int v = p[i].to ; if( !p[i].flow || dis[v] != -1 ) continue ; dis[v] = dis[u] + 1 , que[++ba] = v ; } } return dis[T] != -1 ; } int dfs( int u , int flow ){ if( u == T ) return flow ; int rt = 0 ; for( int i = head[u] ; i ; i = p[i].pre ){ int v = p[i].to , nowf ; if( dis[v] != dis[u] + 1 || !p[i].flow ) continue ; if( ( nowf = dfs( v , min( p[i].flow , flow ) ) ) ){ p[i].flow -= nowf , p[i^1].flow += nowf ; flow -= nowf , rt += nowf ; } } if( flow ) dis[u] = -1 ; return rt ; } void solve(){ int ans = 0 ; while( BFS() ) ans += dfs( S , 0x3f3f3f3f ) ; printf( "%d" , ans ) ; } int main(){ scanf( "%d%d" , &M , &N ) , S = N + 1 , T = N + 2 ; for( int i = 1 ; i <= M ; i ++ ) scanf( "%d" , &a[i] ) ; for( int i = 1 , c ; i <= N ; i ++ ){ scanf( "%d" , &c ) ; for( int j = 1 , t ; j <= c ; j ++ ){ scanf( "%d" , &t ) ; if( !pre[t] ) In( S , i , a[t] ) ; else acce[ pre[t] ][i] = true ; pre[t] = i ; } scanf( "%d" , &c ) , In( i , T , c ) ; } for( int i = 1 ; i <= N ; i ++ ) for( int j = 1 ; j <= N ; j ++ ) if( acce[i][j] ) In( i , j , 0x3f3f3f3f ) ; solve() ; }