●洛谷 1251 餐巾计划问题

●题链:

https://www.luogu.org/problemnew/show/1251

●题解:

一点启示:建图时要考虑到流量问题,即为了方便使用最小费用最大流算法,要把流量最大时为最终目的考虑进建图。
拆点,每天拆为两个点i, i',表示每天开始和每天结束
(s,i,ai,P):在第i天最多买ri个餐巾,花费为P;
(i,t,ai,0):第i天要用ai块餐巾;
(s,i',ai,0):第i天用剩的ai块旧餐巾;
(i',i+M,INF,F):第i天的旧餐巾送到快洗部,花费为F;
(i',i+N,INF,S):第i天的旧餐巾送到慢洗部,花费为S;
(i,i+1,INF,0):第i天的没用的餐巾可以留到第i+1天去用。

 

SPFA费用流:

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 2050
#define INF 0x3f3f3f3f
using namespace std;
struct Edge{
	int to[MAXN*12],cap[MAXN*12],cot[MAXN*12],nxt[MAXN*12],head[MAXN*2],ent;
	void Init(){
		ent=2; memset(head,0,sizeof(head));
	}
	void Adde(int u,int v,int w,int c){
		to[ent]=v; cap[ent]=w; cot[ent]=c;
		nxt[ent]=head[u]; head[u]=ent++;
		to[ent]=u; cap[ent]=0; cot[ent]=-c;
		nxt[ent]=head[v]; head[v]=ent++;
	}
	int Next(int i,bool type){
		return type?head[i]:nxt[i];
	}
}E;
int a[MAXN];
int Day,P,M,F,N,S,SS,TT;
int idx(int i,int k){
	return i+Day*k;
}
bool spfa(long long &cost){
	static bool inq[MAXN*2];
	static int dis[MAXN*2],p[MAXN*2],flow[MAXN*2];
	memset(dis,0x3f,sizeof(dis));
	queue<int>q;
	q.push(SS); inq[SS]=1; dis[SS]=0; flow[SS]=INF;
	while(!q.empty()){
		int u=q.front(); q.pop(); inq[u]=0;
		for(int i=E.Next(u,1);i;i=E.Next(i,0)){
			int v=E.to[i];
			if(!E.cap[i]||dis[v]<=dis[u]+E.cot[i]) continue;
			dis[v]=dis[u]+E.cot[i]; p[v]=i; flow[v]=min(flow[u],E.cap[i]);
			if(!inq[v]) inq[v]=1,q.push(v);
		}
	}
	if(dis[TT]==INF) return 0;
	int u=TT; cost+=1ll*flow[TT]*dis[TT];
	while(u!=SS){
		E.cap[p[u]]-=flow[TT];
		E.cap[p[u]^1]+=flow[TT];
		u=E.to[p[u]^1];
	}
	return 1;
}
long long Mincost_Maxflow(){
	long long cost=0;
	while(spfa(cost));
	return cost;
}
int main()
{
	E.Init();	
	scanf("%d",&Day); SS=2*Day+1; TT=2*Day+2;
	for(int i=1;i<=Day;i++){
		scanf("%d",&a[i]);
		E.Adde(SS,idx(i,1),a[i],0);
		E.Adde(idx(i,0),TT,a[i],0);
	}
	scanf("%d%d%d%d%d",&P,&M,&F,&N,&S);
	for(int i=1,_i;i<=Day;i++){
		E.Adde(SS,idx(i,0),a[i],P);
		_i=i+M; if(_i<=Day) E.Adde(idx(i,1),idx(_i,0),INF,F);
		_i=i+N; if(_i<=Day) E.Adde(idx(i,1),idx(_i,0),INF,S);
	}
	for(int i=1;i<=Day;i++){
		if(i!=Day) E.Adde(idx(i,0),idx(i+1,0),INF,0);
	}
	long long ans=Mincost_Maxflow();
	printf("%lld",ans);
	return 0;
}

ZKW(dinic实现)费用流:

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 2050
#define INF 0x3f3f3f3f
using namespace std;
struct Edge{
	int to[MAXN*12],cap[MAXN*12],cot[MAXN*12],nxt[MAXN*12],head[MAXN*2],ent;
	void Init(){
		ent=2; memset(head,0,sizeof(head));
	}
	void Adde(int u,int v,int w,int c){
		to[ent]=v; cap[ent]=w; cot[ent]=c;
		nxt[ent]=head[u]; head[u]=ent++;
		to[ent]=u; cap[ent]=0; cot[ent]=-c;
		nxt[ent]=head[v]; head[v]=ent++;
	}
	int Next(int i,bool type){
		return type?head[i]:nxt[i];
	}
}E;
int a[MAXN],cur[MAXN*2],dis[MAXN*2];
int Day,P,M,F,N,S,SS,TT;
int idx(int i,int k){
	return i+Day*k;
}
bool spfa(){
	static bool inq[MAXN*2];
	memset(dis,0x3f,sizeof(dis));
	queue<int>q;
	q.push(TT); inq[TT]=1; dis[TT]=0;
	while(!q.empty()){
		int u=q.front(); q.pop(); inq[u]=0;
		for(int i=E.Next(u,1);i;i=E.Next(i,0)){
			int v=E.to[i];
			if(!E.cap[i^1]||dis[v]<=dis[u]+E.cot[i^1]) continue;
			dis[v]=dis[u]+E.cot[i^1];
			if(!inq[v]) inq[v]=1,q.push(v);
		}
	}
	return dis[SS]<INF;
}
int dfs(int u,int reflow){
	if(u==TT||reflow==0) return reflow;
	int flowout=0,f,d=dis[u]; dis[u]=INF;
	for(int &i=cur[u];i;i=E.Next(i,0)){
		int v=E.to[i];
		if(d!=dis[v]+E.cot[i]||!E.cap[i]) continue;
		f=dfs(v,min(reflow,E.cap[i]));
		flowout+=f; E.cap[i^1]+=f;
		reflow-=f;	E.cap[i]-=f;
		if(!reflow) break;
	}
	return flowout;
}
long long ZKW_Mincost(){
	long long cost=0;
	while(spfa()){
		memcpy(cur,E.head,sizeof(E.head));
		cost+=1ll*dis[SS]*dfs(SS,INF);
	}
	return cost;
}
int main()
{
	E.Init();	
	scanf("%d",&Day); SS=2*Day+1; TT=2*Day+2;
	for(int i=1;i<=Day;i++){
		scanf("%d",&a[i]);
		E.Adde(SS,idx(i,1),a[i],0);
		E.Adde(idx(i,0),TT,a[i],0);
	}
	scanf("%d%d%d%d%d",&P,&M,&F,&N,&S);
	for(int i=1,_i;i<=Day;i++){
		E.Adde(SS,idx(i,0),a[i],P);
		_i=i+M; if(_i<=Day) E.Adde(idx(i,1),idx(_i,0),INF,F);
		_i=i+N; if(_i<=Day) E.Adde(idx(i,1),idx(_i,0),INF,S);
	}
	for(int i=1;i<=Day;i++){
		if(i!=Day) E.Adde(idx(i,0),idx(i+1,0),INF,0);
	}
	long long ans=ZKW_Mincost();
	printf("%lld",ans);
	return 0;
}
posted @ 2017-11-30 19:56  *ZJ  阅读(134)  评论(0编辑  收藏  举报