[洛谷P1251]餐巾计划问题
题目大意:一个餐厅N天,每天需要$r_i$块餐巾。每块餐巾需要p元,每天用过的餐巾变脏,不能直接用。现在有快洗店和慢洗店,快洗店洗餐巾需要m天,每块花费f元;慢洗店洗餐巾需要n天,每块餐巾s元(m < n,s< f)。现要求最新的花费使满足每天所需。
题解:把每天拆点,变成上午和下午,进行连边,跑费用流
卡点:现TLE60
C++ Code:
#include<cstdio> #include<cctype> #include<cstring> #define maxn 4010 using namespace std; const long long inf=0x3f3f3f3f3f3f3f3f; int n,t1,t2; long long d[maxn],a,m,m1,m2; int q[maxn],h,t,pre[maxn]; int st=1,ed; int head[maxn],cnt=2; bool vis[maxn]; struct Edge{ int to,nxt; long long w,cost; }e[maxn*1000]; char ch; void read(int &x){ ch=getchar(); while (!isdigit(ch))ch=getchar(); for (x=ch^48,ch=getchar();isdigit(ch);ch=getchar())x=x*10+(ch^48); } void readLL(long long &x){ ch=getchar(); while (!isdigit(ch))ch=getchar(); for (x=ch^48,ch=getchar();isdigit(ch);ch=getchar())x=x*10+(ch^48); } inline long long min(long long a,long long b){return a<b?a:b;} void add(int a,int b,long long c,long long d){ e[cnt]=(Edge){b,head[a],c,d};head[a]=cnt; e[cnt^1]=(Edge){a,head[b],0,-d};head[b]=cnt^1; cnt+=2; } bool spfa(){ int x; memset(d,0x3f,sizeof d); d[q[h=t=1]=st]=0; while (h<=t){ vis[x=q[h++]]=false; for (int i=head[x];i;i=e[i].nxt){ int to=e[i].to; if (e[i].w&&d[to]>d[x]+e[i].cost){ d[to]=d[x]+e[i].cost; pre[to]=i; if (!vis[to])vis[q[++t]=to]=true; } } } // printf("%lld\n",d[ed]); return d[ed]!=inf; } long long update(){ long long ans,mf=inf; for (int i=pre[ed];i;i=pre[e[i^1].to])mf=min(mf,e[i].w); ans=mf*d[ed]; for (int i=pre[ed];i;i=pre[e[i^1].to])e[i].w-=mf,e[i^1].w+=mf; return ans; } void MCMF(){ long long ans=0; while (spfa())ans+=update(); printf("%lld\n",ans); } int main(){ read(n); // printf("%lld\n",inf); ed=n+1<<1; for (int i=1;i<=n;i++)readLL(a),add(st,i+1,a,0),add(i+n+1,ed,a,0); readLL(m),read(t1),readLL(m1),read(t2),readLL(m2); for(int i=1;i<=n;i++){ if(i+1<=n)add(i+1,i+2,inf,0); if(i+t1<=n)add(i+1,i+n+t1+1,inf,m1); if(i+t2<=n)add(i+1,i+n+t2+1,inf,m2); add(st,i+n+1,inf,m); } MCMF(); return 0; }