最小费用最大流。动态加点。
可以先去做bzoj1070修车,题意基本一样,数据范围较小。
懒得再写一遍了——>类似的题解
但是这道题数据范围较大直接建图会TLE,所以要动态加点。
开始时每个厨师只建一个点表示倒数第一个做的菜。
然后增广一次,ans1加上费用,ans2加上流量,找出增广了哪个厨师(判断满流边),加入一个点代表此厨师倒数第x+1做的菜,然后连边继续增广。
结束条件是总流量等于总菜数……
1 #include2 #include 3 #include 4 #include 5 #include 6 using namespace std; 7 const int dian=100005; 8 const int bian=500005; 9 const int INF=0x3f3f3f3f; 10 int h[dian],hh[dian],nxt[bian],ver[bian],val[bian],cos[bian]; 11 int d[dian],v[dian],minn[dian],with[dian],map[105][45]; 12 int ceng[105]; 13 int n,m,tot,aa,ans,anss; 14 int S,T; 15 void add(int a,int b,int c,int d){ 16 tot++;ver[tot]=b;val[tot]=c;cos[tot]=d;nxt[tot]=h[a];h[a]=tot; 17 tot++;ver[tot]=a;val[tot]=0;cos[tot]=-d;nxt[tot]=h[b];h[b]=tot; 18 } 19 bool tell(){ 20 memset(v,0,sizeof(v)); 21 memset(d,0x3f,sizeof(d)); 22 memset(with,0,sizeof(with)); 23 memset(minn,0x3f,sizeof(minn)); 24 queue<int>q; 25 q.push(S); 26 v[S]=1; 27 d[S]=0; 28 while(!q.empty()){ 29 int x=q.front(); 30 q.pop(); 31 v[x]=0; 32 for(int i=h[x];i;i=nxt[i]){ 33 int y=ver[i]; 34 if(d[y]>d[x]+cos[i]&&val[i]){ 35 d[y]=d[x]+cos[i]; 36 minn[y]=min(minn[x],val[i]); 37 with[y]=i; 38 if(!v[y]){ 39 v[y]=1; 40 q.push(y); 41 } 42 } 43 } 44 } 45 if(d[T]==0x3f3f3f3f) 46 return false; 47 return true; 48 } 49 int zeng(){ 50 for(int i=T;i!=S;i=ver[with[i]^1]){ 51 val[with[i]]-=minn[T]; 52 val[with[i]^1]+=minn[T]; 53 } 54 return minn[T]*d[T]; 55 } 56 int dinic_cost(){ 57 int r=0; 58 if(tell()) 59 r+=zeng(); 60 return r; 61 } 62 int main(){ 63 memset(h,0,sizeof(h)); 64 memset(nxt,0,sizeof(nxt)); 65 tot=1; 66 ans=0; 67 anss=0; 68 scanf("%d%d",&n,&m); 69 S=800*m+n+1,T=800*m+n+2; 70 for(int i=1;i<=n;i++){ 71 scanf("%d",&aa); 72 ans+=aa; 73 add(S,i,aa,0); 74 } 75 for(int i=1;i<=n;i++) 76 for(int j=1;j<=m;j++) 77 scanf("%d",&map[j][i]); 78 for(int i=1;i<=m;i++){ 79 add(n+i,T,1,0); 80 hh[n+i]=tot-1; 81 ceng[i]=1; 82 } 83 for(int i=1;i<=n;i++) 84 for(int j=1;j<=m;j++) 85 add(i,n+j,1,map[j][i]); 86 while(ans--){ 87 anss+=dinic_cost(); 88 int hhdh,hhdl; 89 for(int i=1;i<=m;i++) 90 if(!val[hh[n+(ceng[i]-1)*m+i]]){ 91 hhdh=ceng[i],hhdl=i; 92 ceng[i]++; 93 break; 94 } 95 for(int i=1;i<=n;i++) 96 add(i,n+hhdh*m+hhdl,1,map[hhdl][i]*(hhdh+1)); 97 add(n+hhdh*m+hhdl,T,1,0); 98 hh[n+hhdh*m+hhdl]=tot-1; 99 } 100 printf("%d",anss); 101 return 0; 102 }
注意常数!注意数组大小!