网络流 xoj 1247: 餐巾计划问题 题解
根据题意,不难发现题目要求求出最小费用流,这题难在建模。
首先我们找到限制条件,也就是每天需要的餐巾数量。每天的餐巾既有进又有出(即旧餐巾)。不妨将旧餐巾看做从源点(建一个源点),到1~N点的流量,费用为0,表示每天获得的旧餐巾,需要处理。然后再多建(N+1)~(N+N)这N个点,与汇点(建一个汇点)的连边为每天需要的餐巾数。
再根据题目给出的三种获得新餐巾的方式(一种直接购买;两种处理旧餐巾,分别是快洗和慢洗)。处理旧餐巾可以连1~N到(N+1)~(N+N)的边,表示(N+1)~(N+N)这些天的新餐巾可以通过1~N中某(几)天的旧餐巾经过处理后得到的。连边即 (i,i+N+tf,inf,pf) 和 (i,i+N+ts,inf,ps) 。tf是快洗的时间,pf 是快洗的费用;ts,ps分别是慢洗的时间和费用。边:(起点,终点,流量,费用)。
不要漏了,每天可以将旧餐巾留到后一天,所以多建 (i,i+1,inf,0) 。然后就是购买的餐巾直接连接源点与(N+1)~(N+N),费用为p,流量为inf。
具体代码如下:
#include <iostream>
#include <cstdio>
#include <queue>
#define _(d) while(d (((ch=getchar())>47)&&ch<58))
using namespace std;
const int MaxN=1005<<2,Maxe=1005*1005;
const int inf=0x7fffffff;
int N,p,pf,ps,tf,ts;//days,fee of buy,fee of fast/slow ones,times of fast/slow ones;
int ans,h[MaxN],d[MaxN],pre[MaxN];
bool vst[MaxN];
int S,T,tt,from[Maxe],to[Maxe],flow[Maxe],cst[Maxe],nxt[Maxe];//edge
inline void Get(int &x){char ch;_(!);x=ch-48;_()x=(x<<3)+(x<<1)+ch-48;}
inline void addedge(int u,int v,int w,int cc)
{
from[tt]=u;to[tt]=v;flow[tt]=w;cst[tt]=cc;
nxt[tt]=h[u];h[u]=tt++;
}
inline void add(int u,int v,int w,int cc)
{
addedge(u,v,w,cc);addedge(v,u,0,-cc);
}
queue<int> q;
int spfa()
{
for(int i=0;i<MaxN;i++) vst[i]=0,d[i]=inf,pre[i]=-1;
q.push(S);
vst[S]=1;d[S]=0;
while(!q.empty())
{
int u=q.front();q.pop();
vst[u]=0;
for(int i=h[u];i!=-1;i=nxt[i])
{
int v=to[i];
if(flow[i]>0&&d[v]>d[u]+cst[i])
{
d[v]=d[u]+cst[i];
pre[v]=i;
if(!vst[v])
{
vst[v]=1;
q.push(v);
}
}
}
}
return d[T]<inf;
}
void work()
{
while(spfa())
{
int ft=inf;
for(int i=T;i!=S;i=from[pre[i]]){int k=pre[i];ft=min(ft,flow[k]);}
for(int i=T;i!=S;i=from[pre[i]])
{
int k=pre[i];
ans+=cst[k]*ft;
flow[k]-=ft;
flow[k^1]+=ft;
}
}
return ;
}
int main()
{
freopen("1247.in","r",stdin);
for(int i=0;i<MaxN;i++) h[i]=-1;
int t1;
Get(N);Get(p);Get(tf);Get(pf);Get(ts);Get(ps);
T=2001;
for(int i=1;i<=N;i++)
{
Get(t1);
add(S,i,t1,0);
add(i+N,T,t1,0);
if(i+1<=N) add(i,i+1,inf,0);//将旧餐巾留到第二天洗
if(i+N+tf<=2*N) add(i,i+N+tf,inf,pf);//将旧餐巾给快洗
if(i+N+ts<=2*N) add(i,i+N+ts,inf,ps);//将旧餐巾给慢洗
add(S,i+N,inf,p);
}
work();
printf("%d\n",ans);
return 0;
}