[BZOJ1280]-Emmy賣豬pigs-網路流
阿新 • • 發佈:2018-11-11
說在前面
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() ;
}