P1251 餐巾計劃問題 網路流之最小費用流
阿新 • • 發佈:2018-12-16
P1251 因為是一天中有不同的事務,現將一天拆點為晚上i 和早上i+N。 流向i的流是髒毛巾,流向早上的為乾淨毛巾。 建圖: 設一源點s,匯點t。
- s - > i 流量x,花費0. 表示到晚上有x條髒毛巾產生。
- i + N -> t ,流量 x , 花費0 .表示每天早上向匯點提供x條幹淨毛巾,如果滿流,則此天的毛巾夠用。
- i -> i + 1 . 流量INF , 花費0 。表示第i天晚上的髒毛巾可以不洗,留到i+1天晚上。
- i -> i + N + m . 流量INF ,花費fs 。表示第i天晚上的髒毛巾可以送去快洗,到i+m天早上可以用。
- i -> i + N + n . 流量INF,花費sl。表示第i天晚上的髒毛巾可以送去慢西,到弟i+n天早上可以用。
- s -> i + N ,流量INF,花費p。表示早上可以購買毛巾。 Code:
#include <bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
const int AX = 5e4 + 666 ;
struct Node{
int u , v , next1 , flow , cost ;
Node( int u = 0 , int v = 0 , int flow = 0 , int cost = 0 , int next1 = 0 ):u(u),v(v),flow (flow),cost(cost),next1(next1){}
}G[AX*10];
int head[AX];
LL dis[AX] ;
int pre[AX] ;
int idx[AX*10] ;
int fl[AX] ;
int tot ;
int s, t ;
bool vis[AX] ;
void addEdge( int u , int v , int w , int c ){
G[tot] = Node( u , v , w , c , head[u] ) ; head[u] = tot ++ ;
G[tot] = Node( v , u , 0 , -c, head[ v] ) ; head[v] = tot ++ ;
}
int SPFA( ){
memset( dis , INF , sizeof(dis) ) ;
memset( fl , INF , sizeof(fl) ) ;
memset( vis , false , sizeof(vis) ) ;
queue<int>q ;
q.push(s) ;
dis[s] = 0 ;
pre[t] = 0 ;
while( !q.empty() ) {
int u = q.front(); q.pop() ;
vis[u] = false;
for( int i = head[u] ; ~i ; i = G[i].next1 ) {
int v = G[i].v ;
if( G[i].flow && dis[u] + G[i].cost < dis[v] ){
dis[v] = dis[u] + G[i].cost ;
pre[v] = u ;
idx[v] = i ;
fl[v] = min( fl[u] , G[i].flow ) ;
if( !vis[v] ){
vis[v] = true ;
q.push(v) ;
}
}
}
}return pre[t] ;
}
int main(){
int N ;
tot = 0 ;
memset( head , -1, sizeof(head) ) ;
scanf("%d",&N) ;
int x ;
s = 0 ;
t = 2 * N + 1 ;
for( int i = 1 ; i <= N ; i++ ){
scanf("%d",&x);
addEdge( s , i , x , 0 ) ;
addEdge( i + N , t , x , 0 ) ;
}
int p , m , fs , n , sl ;
scanf("%d%d%d%d%d",&p,&m,&fs,&n,&sl);
for( int i = 1 ; i <= N ; i++ ){
if( i + 1 <= N ) addEdge( i , i + 1 , INF , 0 ) ;
if( i + m <= N ) addEdge( i , i + m + N , INF , fs ) ;
if( i + n <= N ) addEdge( i , i + n + N , INF , sl ) ;
addEdge( s , i + N , INF , p ) ;
}
LL rs_cost = 0 ;
while( SPFA() ){
rs_cost += 1LL* fl[t] * dis[t] ;
for( int i = t ; i != s ; i = pre[i] ){
G[idx[i]].flow -= fl[t] ;
G[idx[i]^1].flow += fl[t] ;
}
}
printf("%lld\n",rs_cost);
return 0 ;
}