说在前面
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() ;
}