把每一天看作一个点,每一天的志愿者数目就是流量限制,从i到i+1连边,上下界就是(A[i],+inf)。
对于每一类志愿者,从T[i]+1到S[i]连边,费用为招募一个志愿者的费用,流量为inf。这样每多1的流量,就多了一个从S[i]到T[i]+1的循环流。
求一遍无源汇的最小费用可行流就可以了。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<queue> 6 #define inf 0x3f3f3f3f 7 #define N 100005 8 using namespace std; 9 int n,m; 10 int v[N]; 11 int head[N],ver[N],nxt[N],tot,f[N],quan[N]; 12 void add(int a,int b,int c,int d) 13 { 14 tot++;nxt[tot]=head[a];head[a]=tot;ver[tot]=b;quan[tot]=d;f[tot]=c; 15 tot++;nxt[tot]=head[b];head[b]=tot;ver[tot]=a;quan[tot]=-d;f[tot]=0; 16 return ; 17 } 18 int S,T; 19 int dis[2005],in[2005],with[2005],mn[2005]; 20 bool tell() 21 { 22 memset(dis,0x3f,sizeof(dis)); 23 memset(in,0,sizeof(in)); 24 dis[S]=0;mn[S]=inf; 25 queue<int>q; 26 q.push(S); 27 while(!q.empty()) 28 { 29 int tmp=q.front();q.pop();in[tmp]=0; 30 for(int i=head[tmp];i;i=nxt[i]) 31 { 32 if(dis[ver[i]]>dis[tmp]+quan[i]&&f[i]) 33 { 34 dis[ver[i]]=dis[tmp]+quan[i]; 35 with[ver[i]]=i;mn[ver[i]]=min(f[i],mn[tmp]); 36 if(!in[ver[i]])in[ver[i]]=1,q.push(ver[i]); 37 } 38 } 39 } 40 return dis[T]!=inf; 41 } 42 int zeng() 43 { 44 for(int i=T;i;i=ver[with[i]^1]) 45 { 46 f[with[i]]-=mn[T];f[with[i]^1]+=mn[T]; 47 } 48 return mn[T]*dis[T]; 49 } 50 int main() 51 { 52 scanf("%d%d",&n,&m); 53 S=0;T=n+2; 54 tot=1; 55 int tmp; 56 for(int i=1;i<=n;i++) 57 { 58 scanf("%d",&tmp); 59 add(i,T,tmp,0); 60 add(S,i+1,tmp,0); 61 add(i,i+1,inf,0); 62 } 63 int t1,t2,t3; 64 for(int i=1;i<=m;i++) 65 { 66 scanf("%d%d%d",&t1,&t2,&t3); 67 add(t2+1,t1,inf,t3); 68 } 69 int ans=0; 70 while(tell())ans+=zeng(); 71 printf("%d ",ans); 72 return 0; 73 }