题目:洛谷P3980。
题目大意:
有n天,每天需要至少(a_i)个人。现在有m种人,每种人可以在第(s_i)到第(t_i)天工作,花费(c_i)的价值。
问至少花费多少价值才能满足需要(保证一定有解)。
解题思路:
网络流。把每天当做一个节点,向下一个节点连容量INF-(a_i),费用0的边。
然后对于每个人,从(s_i)向(t_i +1)连容量为INF,费用为(c_i)的边。
最后从1到n+1跑费用流,费用即答案。
主要思路就是把需要的人数挖掉,然后让志愿者填满剩下的容量。
C++ Code:
#include<bits/stdc++.h> #define S 0 #define N 1007 #define inf 0x3f3f3f inline int readint(){ int c=getchar(),d=0; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^'0'); return d; } int n,m,T,head[N],cnt=1,dis[N],pre_e[N],a[N]; bool vis[N]; int q[300002]; struct edge{ int from,to,cap,cost,nxt; }e[N<<5]; inline void addedge(const int from,const int to,const int cap,const int cost){ e[++cnt]=(edge){from,to,cap,cost,head[from]}; head[from]=cnt; e[++cnt]=(edge){to,from,0,-cost,head[to]}; head[to]=cnt; } bool spfa(int& flow,int& cost){ memset(dis,0x3f,sizeof dis); memset(pre_e,0,sizeof pre_e); memset(a,0x3f,sizeof a); memset(vis,0,sizeof vis); dis[S]=0; vis[S]=1; q[1]=S; int l=0,r=1; while(l!=r){ int u=q[l=l%300000+1]; vis[u]=0; for(int i=head[u];i!=-1;i=e[i].nxt) if(e[i].cap&&dis[e[i].to]>dis[u]+e[i].cost){ dis[e[i].to]=dis[u]+e[i].cost; a[e[i].to]=std::min(e[i].cap,a[u]); pre_e[e[i].to]=i; if(!vis[e[i].to]){ vis[e[i].to]=1; q[r=r%300000+1]=e[i].to; } } } if(dis[T]==0x3f3f3f3f)return 0; flow+=a[T]; cost+=dis[T]*a[T]; for(int i=T;i!=S;i=e[pre_e[i]].from){ e[pre_e[i]].cap-=a[T]; e[pre_e[i]^1].cap+=a[T]; } return 1; } int main(){ T=(n=readint())+2,m=readint(); memset(head,-1,sizeof head); addedge(S,1,inf,0); addedge(n+1,T,inf,0); for(int i=1;i<=n;++i)addedge(i,i+1,inf-readint(),0); for(int i=1;i<=m;++i){ int s=readint(),t=readint(),C=readint(); addedge(s,t+1,inf,C); } int flow=0,cost=0; while(spfa(flow,cost)); printf("%d ",cost); return 0; }