【中学高级本-网络流24题】餐巾计划
把每天分为二分图两个集合中的顶点Xi,Yi,建立附加源S汇T。
1、从S向每个Xi连一条容量为ri,费用为0的有向边。
表示第i天还剩ri条餐巾。
2、从每个Yi向T连一条容量为ri,费用为0的有向边。
控制最大流。
3、从S向每个Yi连一条容量为无穷大,费用为p的有向边。
表示买餐巾。
4、从每个Xi向Xi+1(i+1<=N)连一条容量为无穷大,费用为0的有向边。
表示第i天剩的餐巾可以留给第i+1天。
5、从每个Xi向Yi+m(i+m<=N)连一条容量为无穷大,费用为f的有向边。
表示快洗。
6、从每个Xi向Yi+n(i+n<=N)连一条容量为无穷大,费用为s的有向边。
表示慢洗。
然后就求最小费用最大流就可以了。
1 #include<set> 2 #include<map> 3 #include<queue> 4 #include<stack> 5 #include<ctime> 6 #include<cmath> 7 #include<string> 8 #include<vector> 9 #include<cstdio> 10 #include<cstdlib> 11 #include<cstring> 12 #include<iostream> 13 #include<algorithm> 14 #define inf 1999999999 15 using namespace std; 16 struct data{ 17 int nex,to,w,c; 18 }e[2610]; 19 int head[410],edge=-1,dis[410],vis[410],pre[410]; 20 void add(int from,int to,int w,int c){ 21 e[++edge].nex=head[from]; 22 e[edge].to=to; 23 e[edge].w=w; 24 e[edge].c=c; 25 head[from]=edge; 26 } 27 inline int SPFA(int s,int t){ 28 queue<int>q; 29 q.push(s); 30 memset(dis,127,sizeof(dis));int zd=dis[0]; 31 memset(vis,0,sizeof(vis)); 32 dis[s]=0,vis[s]=1; 33 while(!q.empty()){ 34 int u=q.front();q.pop(); 35 vis[u]=0; 36 for(int i=head[u];i!=-1;i=e[i].nex){ 37 int v=e[i].to; 38 if(e[i].w>0 && dis[v]>dis[u]+e[i].c){ 39 dis[v]=dis[u]+e[i].c; 40 pre[v]=i; 41 if(!vis[v])q.push(v),vis[v]=1; 42 } 43 } 44 } 45 if(dis[t]==zd) return 0; 46 else return 1; 47 } 48 inline int end(int s,int t){ 49 int ans=0,p=0,sum=inf; 50 for(int u=t;u!=s;u=e[p^1].to) 51 p=pre[u],sum=min(sum,e[p].w); 52 for(int u=t;u!=s;u=e[p^1].to){ 53 p=pre[u]; 54 e[p].w-=sum; 55 e[p^1].w+=sum; 56 ans+=e[p].c*sum; 57 } 58 return ans; 59 } 60 inline int solve(int s,int t){ 61 int flow=0; 62 while(SPFA(s,t)) flow+=end(s,t); 63 return flow; 64 } 65 int main() 66 { 67 freopen("!.in","r",stdin); 68 freopen("!.out","w",stdout); 69 memset(head,-1,sizeof(head)); 70 int n,p,k,fk,m,fm,x; 71 scanf("%d",&n);int s=0,t=2*n+1; 72 for(int i=1;i<=n;i++) 73 scanf("%d",&x),add(s,i,x,0),add(i,s,0,0),add(i+n,t,x,0),add(t,i+n,0,0); 74 scanf("%d%d%d%d%d",&p,&k,&fk,&m,&fm); 75 for(int i=2;i<=n;i++) 76 add(i-1,i,inf,0),add(i,i-1,0,0); 77 for(int i=1;i<=n;i++){ 78 if(i-k>0) add(i-k,i+n,inf,fk),add(i+n,i-k,0,-fk); 79 if(i-m>0) add(i-m,i+n,inf,fm),add(i+n,i-m,0,-fm); 80 add(s,n+i,inf,p),add(n+i,s,0,-p); 81 } 82 printf("%d",solve(s,t)); 83 return 0; 84 }