[NOI2012]美食节(费用流+动态开点)
2015-04-26 01:02
302 查看
【题解】
费用流:
首先确定:每一单位的流量代表一位厨师做一份菜品,费用代表花费的时间
每位厨师做同一道菜,每一份时间也是不同的,因此将每个厨师拆成p个点
建边需要确定的费用与做菜顺序有关,而后做的菜对先做的菜是没有影响的,所以倒着处理,拆成的第i个点表示每位厨师做的倒数第i道菜
建图:
s -> n种菜品 容量为pi,费用为0
第i种菜品 -> 第j位厨师拆成的第k个点 容量为1,费用为 k*T[i][j]
第j位厨师拆成的第k个点 -> t 容量为1,费用为0
每次增流只会增1个单位,所以共增流p次,边数约为m*p*n,因此,复杂度为:O(m*n*p^2) 会TLE
动态建点:
开始时只允许每个厨师做"倒数第一道菜",只为做完当前菜的那个厨师安排下一道菜,因为更新的流不会从t出发,所以该算法正确
【代码】
费用流:
首先确定:每一单位的流量代表一位厨师做一份菜品,费用代表花费的时间
每位厨师做同一道菜,每一份时间也是不同的,因此将每个厨师拆成p个点
建边需要确定的费用与做菜顺序有关,而后做的菜对先做的菜是没有影响的,所以倒着处理,拆成的第i个点表示每位厨师做的倒数第i道菜
建图:
s -> n种菜品 容量为pi,费用为0
第i种菜品 -> 第j位厨师拆成的第k个点 容量为1,费用为 k*T[i][j]
第j位厨师拆成的第k个点 -> t 容量为1,费用为0
每次增流只会增1个单位,所以共增流p次,边数约为m*p*n,因此,复杂度为:O(m*n*p^2) 会TLE
动态建点:
开始时只允许每个厨师做"倒数第一道菜",只为做完当前菜的那个厨师安排下一道菜,因为更新的流不会从t出发,所以该算法正确
【代码】
#include<stdio.h> #include<stdlib.h> #define INF 1000000000 int u[80000]={0},v[80000]={0},cap[80000]={0},flow[80000]={0},cost[80000]={0},first[1000]={0},next[80000]={0}; int T[50][150]={0},q[1000000]={0},d[1000]={0},p[1000]={0},hash[1000]={0},id[1000]={0},len[50]={0}; int e=0; void tj(int x,int y,int z,int c) { u[++e]=x; v[e]=y; cap[e]=z; cost[e]=c; next[e]=first[x]; first[x]=e; } int fan(int x) { if(x%2==1) return x+1; return x-1; } int main() { int n,m,count=0,s,t,i,j,node,head,tail,x,a,f=0; scanf("%d%d",&n,&m); s=n+1; node=t=n+2; for(i=1;i<=n;i++) { scanf("%d",&x); count+=x; tj(s,i,x,0); tj(i,s,0,0); } for(i=1;i<=n;i++) for(j=1;j<=m;j++) scanf("%d",&T[i][j]); for(i=1;i<=m;i++) { len[i]=1; id[++node]=i; for(j=1;j<=n;j++) { tj(j,node,1,T[j][i]); tj(node,j,0,-T[j][i]); } tj(node,t,1,0); tj(t,node,0,0); } for(;count>0;count--) { for(i=1;i<=node;i++) { d[i]=INF; hash[i]=0; } d[s]=0; hash[s]=1; head=0; tail=1; q[0]=s; while(head<tail) { for(i=first[q[head]];i!=0;i=next[i]) if(d[v[i]]>d[u[i]]+cost[i]&&cap[i]>flow[i]) { d[v[i]]=d[u[i]]+cost[i]; p[v[i]]=i; if(hash[v[i]]==0) { q[tail++]=v[i]; hash[v[i]]=1; } } hash[q[head++]]=0; } a=INF; for(i=t;i!=s;i=u[p[i]]) if(a>cap[p[i]]-flow[p[i]]) a=cap[p[i]]-flow[p[i]]; for(i=t;i!=s;i=u[p[i]]) { flow[p[i]]+=a; flow[fan(p[i])]-=a; } f+=a*d[t]; x=u[p[t]]; id[++node]=id[x]; len[id[x]]++; for(i=1;i<=n;i++) { tj(i,node,1,T[i][id[node]]*len[id[node]]); tj(node,i,0,-T[i][id[node]]*len[id[node]]); } tj(node,t,1,0); tj(t,node,0,0); } printf("%d",f); return 0; }
相关文章推荐
- 【费用流+动态加边】[NOI2012]美食节
- bzoj 2879: [Noi2012]美食节 费用流+动态加边
- bzoj 2879: [Noi2012]美食节(费用流+动态加边)
- [NOI2012][bzoj2879] 美食节 [费用流+动态加边]
- BZOJ 2879: [Noi2012]美食节( 费用流 + 动态加边 )
- NOI2012 美食节 动态加边维护费用流
- 2879: [Noi2012]美食节 动态加边 费用流
- bzoj2879 [Noi2012]美食节 [费用流动态加边]
- [BZOJ2879][Noi2012]美食节 && 动态加边费用流
- BZOJ 2879 [Noi2012]美食节 | 费用流 动态开点
- BZOJ 2879: [Noi2012]美食节 费用流 动态加边
- bzoj2879 [Noi2012]美食节(动态加边费用流)
- bzoj2879 [NOI2012]美食节(费用流)
- BZOJ2879 [Noi2012]美食节 【费用流】
- BZOJ2879 [Noi2012]美食节 【费用流】
- BZOJ 2879 NOI2012 美食节 费用流
- [BZOJ2879] [NOI2012] 美食节 (费用流)
- 2879: [Noi2012]美食节 (最小费用最大流+动态加边)
- BZOJ 2879: [Noi2012]美食节 最小费用流 动态添边
- BZOJ.2879.[NOI2012]美食节(费用流SPFA)