1. 程式人生 > 其它 >【網路流24題】餐巾計劃問題

【網路流24題】餐巾計劃問題

標籤:費用流

Solution

由於每天餐廳需要 \(r_i\) 份餐巾,產生 \(r_i\) 份需清洗餐巾,考慮將每天拆成兩個點 \(X_i\)\(Y_i\) ,其中 \(X_i\) 需要向匯點 \(T\) 匯入 \(r_i\) 份餐巾,\(Y_i\)\(X_j\) 匯入清洗過的餐巾。

從源點 \(S\)\(X_i\) 連一條容量無限,單位費用為 \(p\) 的邊,表示購買餐巾;向 \(Y_i\) 連一條容量為 \(r_i\),單位費用為 \(0\) 的邊,表示該天用過的餐巾。

此外,\(Y_i\)\(Y_{i+1}\) 連一條容量無限,單位費用為 \(0\) 的邊,表示延期清洗餐巾;分別向 \(X_{i+m}\)

\(X_{i+n}\) 連容量無限,單位費用分別為 \(f\)\(p\) 的邊,表示快洗與慢洗餐巾。

最後跑一邊最小費用最大流即可。

Code

#include<bits/stdc++.h>
#define M 4005
using namespace std;
typedef long long ll;
typedef double db;
char IO;
int rd(){
	int num=0;bool f=0;
	while(IO=getchar(),IO<48||IO>57)if(IO=='-')f=1;
	do num=(num<<1)+(num<<3)+(IO^48);
	while(IO=getchar(),IO>=48&&IO<=57);
	return f?-num:num;
}
bool f2;
int n,m,S,T;
int to[M*12],nxt[M*12],hd[M],cnte=1;
ll val[M*12],cost[M*12];
void Adde(int u,int v,ll w,ll c){
	to[++cnte]=v;val[cnte]=w;cost[cnte]=c;
	nxt[cnte]=hd[u];hd[u]=cnte;
}
void Add(int u,int v,ll w,ll c){
	Adde(u,v,w,c);Adde(v,u,0,-c);
}
ll dep[M];
int cur[M];
bool vis[M];
queue<int> Q;
bool SPFA(){
	memset(dep,63,sizeof(dep));
	memcpy(cur,hd,sizeof(cur));
	dep[S]=1;Q.push(S);
	int u,v;
	while(!Q.empty()){
		u=Q.front();Q.pop();
		vis[u]=0;
		for(int i=hd[u];i;i=nxt[i]){
			v=to[i];
			if(val[i]&&dep[u]+cost[i]<dep[v]){
				dep[v]=dep[u]+cost[i];
				if(!vis[v])Q.push(v),vis[v]=1;
			}
		}
	}
	return dep[T]!=0x3f3f3f3f3f3f3f3f;
}
ll micost;
ll DFS(int u,ll flow){
	if(u==T)return flow;
	vis[u]=1;
	ll res=0,f;
	for(int i=cur[u],v;i;i=nxt[i]){
		cur[u]=i;v=to[i];
		if(vis[v]||dep[v]!=dep[u]+cost[i])continue;
		if(val[i]&&(f=DFS(v,min(flow,val[i])))>0){
			val[i]-=f;val[i^1]+=f;
			res+=f;flow-=f;
			micost+=f*cost[i];
		}
	}
	vis[u]=0;
	return res;
}
ll C[M];
bool f1;
int main(){
//	cout<<1.0*(&f1-&f2)/1024.0/1024.0<<endl;
	n=rd();S=0,T=2*n+1;
	for(int i=1;i<=n;++i)
		C[i]=rd();
	ll p=rd(),a=rd(),f=rd(),b=rd(),s=rd();
	for(int i=1;i<=n;++i){
		Add(S,i,1e18,p);
		Add(i,T,C[i],0);
		Add(S,n+i,C[i],0);
		if(i+a<=n)Add(n+i,i+a,1e18,f);
		if(i+b<=n)Add(n+i,i+b,1e18,s);
		if(i!=n)Add(n+i,n+i+1,1e18,0);
	}
	while(SPFA())DFS(S,1e18);
	cout<<micost;
	return 0;
}