bzoj 2879 [Noi2012]美食节

最小费用最大流。动态加点。

可以先去做bzoj1070修车,题意基本一样,数据范围较小。

懒得再写一遍了——>类似的题解

但是这道题数据范围较大直接建图会TLE,所以要动态加点。

开始时每个厨师只建一个点表示倒数第一个做的菜。

然后增广一次,ans1加上费用,ans2加上流量,找出增广了哪个厨师(判断满流边),加入一个点代表此厨师倒数第x+1做的菜,然后连边继续增广。

结束条件是总流量等于总菜数……

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<algorithm>
  5 #include<queue>
  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 }

 注意常数!注意数组大小!

原文地址:https://www.cnblogs.com/dugudashen/p/6247376.html