把每天分为二分图两个集合中的顶点Xi,Yi,建立附加源S汇T。
1、从S向每个Xi连一条容量为ri,费用为0的有向边。
2、从每个Yi向T连一条容量为ri,费用为0的有向边。
3、从S向每个Yi连一条容量为无穷大,费用为p的有向边。
4、从每个Xi向Xi+1(i+1<=N)连一条容量为无穷大,费用为0的有向边。
5、从每个Xi向Yi+m+1(i+m+1<=N)连一条容量为无穷大,费用为f的有向边。
6、从每个Xi向Yi+n+1(i+n+1<=N)连一条容量为无穷大,费用为s的有向边。
求网络最小费用最大流,费用流值就是要求的最小总花费。
感觉费用流好神奇
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<algorithm>
#include<iostream>
#define MX 200000000
using namespace std;
int sc()
{
int i=0; char c=getchar();
while(c>'9'||c<'0')c=getchar();
while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar();
return i;
}
bool inq[2222];
int dis[2222],q[2222],from[2222],p[2222];
int head[2222],lst[55555],nxt[55555],c[55555],v[55555];
int n,a,b,fa,f,fb,tot=1;
int S,T,ans;
void add(int x,int y,int a,int b)
{
lst[++tot]=y;
c[tot]=a;
v[tot]=b;
nxt[tot]=head[x];
head[x]=tot;
}
void insert(int a,int b,int c,int d){add(a,b,c,d);add(b,a,0,-d);}
bool spfa()
{
for(int i=1; i<=T; i++) dis[i]=MX; dis[S]=0;
int l=1,r=2; q[1]=S;
while(l!=r)
{
int x=q[l++];l%=2200;inq[x]=0;
for(int i=head[x];i;i=nxt[i])
if(c[i]&&dis[x]+v[i]<dis[lst[i]])
{
dis[lst[i]]=dis[x]+v[i];
from[lst[i]]=x;p[lst[i]]=i;
if(!inq[lst[i]])q[r++]=lst[i],r%=2200,inq[lst[i]]=1;
}
}
//cout << dis[T]<<" "<< ans << endl;
return dis[T]!=MX;
}
void mcf()
{
int cc=MX,vv=0;
for(int i=T;i!=S;i=from[i]) cc=min(cc,c[p[i]]);
for(int i=T;i!=S;i=from[i])
{
c[p[i]]-=cc,c[p[i]^1]+=cc;
ans+=cc*v[p[i]];
}
}
int main()
{
n=sc(),a=sc(),b=sc(),f=sc(),fa=sc(),fb=sc();
S=2*n+1,T=S+1;
for(int i=1; i<=n; i++)
{
int x=sc();
insert(S,i,x,0);
insert(i+n,T,x,0);
insert(S,i+n,MX,f);
if(i+a+1<=n)insert(i,i+n+a+1,MX,fa);
if(i+b+1<=n)insert(i,i+n+b+1,MX,fb);
if(i+1<=n)insert(i,i+1,MX,0);
}
while(spfa())mcf();
cout << ans;
}