NOI2012 美食节

http://www.lydsy.com/JudgeOnline/problem.php?id=2879

费用流。

我们发现,每个厨师做的倒数第k道菜对总等待时间的贡献为k*做这道菜的时间。

将每个厨师拆成P个点,第i个第表示这个厨师做倒数第i道菜。

设Vi,j表示第i个厨师做第j道菜的点。

Ui表示第i道菜。

构图:

S->Vi,j一条流量为1,费用为0的边;

Vi,j->Uk一条流量为1,费用为j*t[k][i]的边;

Ui->T一条流量为p[i],费用为0的边。

但是数据范围比较大,我们可以动态加边。

友情题:SDOI2007修车

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<utility>
#include<set>
#include<bitset>
#include<vector>
#include<functional>
#include<deque>
#include<cctype>
#include<climits>
#include<complex>
//#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj

using namespace std;

typedef long long LL;
typedef double DB;
typedef pair<int,int> PII;
typedef complex<DB> CP;

#define mmst(a,v) memset(a,v,sizeof(a))
#define mmcy(a,b) memcpy(a,b,sizeof(a))
#define re(i,a,b)  for(i=a;i<=b;i++)
#define red(i,a,b) for(i=a;i>=b;i--)
#define fi first
#define se second
#define m_p(a,b) make_pair(a,b)
#define SF scanf
#define PF printf
#define two(k) (1<<(k))

template<class T>inline T sqr(T x){return x*x;}
template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}

const DB EPS=1e-9;
inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
const DB Pi=acos(-1.0);

inline int gint()
  {
        int res=0;bool neg=0;char z;
        for(z=getchar();z!=EOF && z!=‘-‘ && !isdigit(z);z=getchar());
        if(z==EOF)return 0;
        if(z==‘-‘){neg=1;z=getchar();}
        for(;z!=EOF && isdigit(z);res=res*10+z-‘0‘,z=getchar());
        return (neg)?-res:res;
    }
inline LL gll()
  {
      LL res=0;bool neg=0;char z;
        for(z=getchar();z!=EOF && z!=‘-‘ && !isdigit(z);z=getchar());
        if(z==EOF)return 0;
        if(z==‘-‘){neg=1;z=getchar();}
        for(;z!=EOF && isdigit(z);res=res*10+z-‘0‘,z=getchar());
        return (neg)?-res:res;
    }

const int maxN=40;
const int maxM=100;
const int maxP=800;
const int INF=1<<30;

int N,M,P;
int p[maxN+10];
int t[maxN+10][maxM+10];
int S,T,now,first[maxN+maxM*maxP+100];
struct Tedge{int u,v,flow,cost,next;}edge[2*(maxN+maxN*maxM*maxP+maxP*maxM)+10000];

inline void addedge(int u,int v,int flow,int cost)
  {
      now++;
      edge[now].u=u;
      edge[now].v=v;
      edge[now].flow=flow;
      edge[now].cost=cost;
      edge[now].next=first[u];
      first[u]=now;
  }
inline void insert(int u,int v,int flow,int cost){addedge(u,v,flow,cost);addedge(v,u,0,-cost);}

int head,tail,que[maxN+maxM*maxP+100];
int vis[maxN+maxM*maxP+100],dis[maxN+maxM*maxP+100],fromedge[maxN+maxM*maxP+100];
inline int SPFA()
  {
      int i;
      re(i,0,N+P*M+1)vis[i]=0,dis[i]=INF,fromedge[i]=-1;
      dis[que[0]=S]=0;
      head=0;tail=1;
      vis[S]=1;
      while(head!=tail)
        {
            int u=que[head++],v,flow,cost;if(head==T)head=0;
            vis[u]=0;
            for(i=first[u],v=edge[i].v,flow=edge[i].flow,cost=edge[i].cost;i!=-1;i=edge[i].next,v=edge[i].v,flow=edge[i].flow,cost=edge[i].cost)
              if(flow>0 && dis[u]+cost<dis[v])
                {
                    dis[v]=dis[u]+cost;
                    fromedge[v]=i;
                    if(!vis[v])
                              {
                                  vis[que[tail]=v]=1;
                                  if(dis[que[tail]]<dis[que[head]])swap(que[head],que[tail]);
                                  tail++;if(tail==T)tail=0;
                                }
                }
        }
      return dis[T]!=INF;
  }
inline void work(int &res)
  {
      int i,x=INF,y,a,b;
      for(i=fromedge[T];i!=-1;i=fromedge[edge[i].u])
          {
              upmin(x,edge[i].flow);
              if(edge[i].u==S)y=edge[i].v,a=(y-1)/P+1,b=y%P+1;
            }
      for(i=fromedge[T];i!=-1;i=fromedge[edge[i].u])edge[i].flow-=x,edge[i^1].flow+=x,res+=x*edge[i].cost;
      re(i,1,N)insert((a-1)*P+b,P*M+i,1,b*t[i][a]);
  }
inline int mincostmaxflow()
  {
      int res=0;
        while(SPFA())work(res);
      return res;
  }

int main()
  {
      freopen("delicacy.in","r",stdin);
      freopen("delicacy.out","w",stdout);
      int i,j;
      N=gint();M=gint();
      mmst(first,-1);now=-1;
      re(i,1,N)p[i]=gint(),P+=p[i];
        re(i,1,N)re(j,1,M)t[i][j]=gint();
        S=0;T=P*M+N+1;
      re(i,1,P*M)insert(S,i,1,0);
        re(i,1,N)insert(P*M+i,T,p[i],0);
        re(i,1,N)re(j,1,M)insert((j-1)*P+1,P*M+i,1,t[i][j]);
      cout<<mincostmaxflow()<<endl;
      return 0;
  }

时间: 2024-12-07 19:59:57

NOI2012 美食节的相关文章

2879: [Noi2012]美食节 - BZOJ

Description CZ市为了欢迎全国各地的同学,特地举办了一场盛大的美食节.作为一个喜欢尝鲜的美食客,小M自然不愿意错过这场盛宴.他很快就尝遍了美食节所有的美食.然而,尝鲜的欲望是难以满足的.尽管所有的菜品都很可口,厨师做菜的速度也很快,小M仍然觉得自己桌上没有已经摆在别人餐桌上的美食是一件无法忍受的事情.于是小M开始研究起了做菜顺序的问题,即安排一个做菜的顺序使得同学们的等待时间最短.小M发现,美食节共有n种不同的菜品.每次点餐,每个同学可以选择其中的一个菜品.总共有m个厨师来制作这些菜

bzoj 2879: [Noi2012]美食节(费用流+动态加边)

2879: [Noi2012]美食节 Time Limit: 10 Sec Memory Limit: 512 MB Submit: 1453 Solved: 778 [Submit][Status][Discuss] Description CZ市为了欢迎全国各地的同学,特地举办了一场盛大的美食节.作为一个喜欢尝鲜的美食客,小M自然不愿意错过这场盛宴.他很快就尝遍了美食节所有的... http://bbs.chinaacc.com/forum-2-3/topic-5785721.html ht

【bzoj2879】[Noi2012]美食节 费用流+动态加边

原文地址:http://www.cnblogs.com/GXZlegend 题目描述 CZ市为了欢迎全国各地的同学,特地举办了一场盛大的美食节.作为一个喜欢尝鲜的美食客,小M自然不愿意错过这场盛宴.他很快就尝遍了美食节所有的美食.然而,尝鲜的欲望是难以满足的.尽管所有的菜品都很可口,厨师做菜的速度也很快,小M仍然觉得自己桌上没有已经摆在别人餐桌上的美食是一件无法忍受的事情.于是小M开始研究起了做菜顺序的问题,即安排一个做菜的顺序使得同学们的等待时间最短.小M发现,美食节共有n种不同的菜品.每次点

bzoj2879 [Noi2012]美食节 [费用流动态加边]

Description CZ市为了欢迎全国各地的同学,特地举办了一场盛大的美食节.作为一个喜欢尝鲜的美食客,小M自然不愿意错过这场盛宴.他很快就尝遍了美食节所有的美食.然而,尝鲜的欲望是难以满足的.尽管所有的菜品都很可口,厨师做菜的速度也很快,小M仍然觉得自己桌上没有已经摆在别人餐桌上的美食是一件无法忍受的事情.于是小M开始研究起了做菜顺序的问题,即安排一个做菜的顺序使得同学们的等待时间最短.小M发现,美食节共有n种不同的菜品.每次点餐,每个同学可以选择其中的一个菜品.总共有m个厨师来制作这些菜

[BZOJ2879] [Noi2012] 美食节 (费用流 &amp; 动态加边)

Description CZ市为了欢迎全国各地的同学,特地举办了一场盛大的美食节.作为一个喜欢尝鲜的美食客,小M自然不愿意错过这场盛宴.他很快就尝遍了美食节所有的美食.然而,尝鲜的欲望是难以满足的.尽管所有的菜品都很可口,厨师做菜的速度也很快,小M仍然觉得自己桌上没有已经摆在别人餐桌上的美食是一件无法忍受的事情.于是小M开始研究起了做菜顺序的问题,即安排一个做菜的顺序使得同学们的等待时间最短.小M发现,美食节共有n种不同的菜品.每次点餐,每个同学可以选择其中的一个菜品.总共有m个厨师来制作这些菜

BZOJ 2879 NOI2012美食节

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2879 CZ市为了欢迎全国各地的同学,特地举办了一场盛大的美食节.作为一个喜欢尝鲜的美食客,小M自然不愿意错过这场盛宴.他很快就尝遍了美食节所有的美食.然而,尝鲜的欲望是难以满足的.尽管所有的菜品都很可口,厨师做菜的速度也很快,小M仍然觉得自己桌上没有已经摆在别人餐桌上的美食是一件无法忍受的事情.于是小M开始研究起了做菜顺序的问题,即安排一个做菜的顺序使得同学们的等待时间最短.小M发现,美食节

[BZOJ2879][Noi2012]美食节(最小费用最大流动态加边)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2879 分析: 和bzoj1070一样,但这题的数据范围大了很多,如果直接建图就会TLE. 因为对于每个厨师对应的分裂成的n个点,一定是前面的点满流后才会可能扩展后面的点.于是可以先把每个厨师的第一个点加入图中,增广一次,然后把对于当前增广的那条路对应的厨师的下一个点加入图中.

bzoj2879: [Noi2012]美食节

费用流加动态建点. 考虑加的点是倒数第几个做的菜,它对答案的共享就是i倍的时间. 和bzoj1070修车那道题一样. #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxk = 100 + 10; const int maxn = 10000 + 10; const int maxm = 2000000 + 10; const int inf =

NOI2012 美食节 解题报告

首先看看BZOJ 1040<修车>,如果没有做,请做完后再来看这道题. 我们惊喜地发现,这道题的题意跟 修车 基本一样.很可惜,数据范围... 我试了一下直接修改 修车 的代码,建成2+n+p*m个点,n*m*p条边的有向图,对其求费用流,时间复杂度O((2+n+p*m)^2*(n*m*p)),实际测试中得到40分. 既然不能做这么庞大的图的网络流,我们考虑动态加点. 刚开始连边: 现在,所有厨师都闲着,那我们把每位厨师做倒数第一道菜的边连向N个点. 然后做费用流. 在增广的过程中,如果k厨师