Task Schedule HDU - 3572

题意

有n个项目, m台机器,一台机器同一时间只能完成一个项目, 一个项目可以在多个机器上完成, 给出这n个项目可以开始建设的时间和截止时间及需要多少天完成, 问是否可以在规定时间内完成所有项目

分析

1 建立模型, 用什么方法解决这种问题, 我们看到一天之内最多可以完成m个工作量, 完成一个项目需要的工作量, 这些都可以用流来表示, 于是选择最大流算法
2 建图, 首先确定什么是结点, 什么是边,
(1) 每一天都可以是一个结点, 经过这个节点的最大流量是m,
(2)其次每个任务都可以是一个结点, 这些结点的流量应该等于该任务的完成时间,
(3) 再次, 确定一个源点和汇点
(4) 可以在源点与任务点之间建立边, 边的容量正是完成该任务的时间
(5)在一个任务的开始和截止时间这些天里, 把每一天都与该任务相连,边的容量为1, 表示一天之内一个任务的总时间只能减少1, 不存在同时做一件任务的情况
(6)在每一天与汇点之间建立边, 边的容量是m
3 建图之后套用dinic算法模版(如要详细了解, 刘汝佳算法竞赛训练指南p358)即

参考代码

const int LEN = 1100;
const int maxn = 1e8;
struct Edge{
  int from,to,cap,flow;
  Edge(int u,int v,int w,int f): from(u),to(v),cap(w),flow(f){}
};
struct Dinic{
   int n,m,s,t;
   vector<Edge> edges;//存边
   vector<int> G[LEN];//结点
   int vis[LEN];//bfs需要标记是否访问过该点
   int d[LEN];//表示源点到该点的层次
   int cur[LEN];//代表dfs已经搜到了那个点
   void init(int n)//初始化
   {
       this->n  = n;
       for(int i = 0;i < n; ++i)
        G[i].clear();
       edges.clear();
   }
   void Add(int u,int v,int w)//添加边
   {
       edges.push_back(Edge(u,v,w,0));
       edges.push_back(Edge(v,u,0,0));
       m = edges.size();
       G[u].push_back(m-2);
       G[v].push_back(m-1);
   }
   bool Bfs(void)//分层
   {
      me(d);
      me(vis);
      d[s] = 0;
      vis[s] = 1;

      queue<int> Q;//队列进行广搜
      Q.push(s);
      while(!Q.empty())
      {
          int q = Q.front();Q.pop();

          for(size_t i = 0;i < G[q].size();++i)
          {
              Edge &tmp = edges[G[q][i]];
              if(!vis[tmp.to]&&tmp.cap>tmp.flow)
              {
                  vis[tmp.to] = 1;
                  d[tmp.to] = d[q] + 1;//结点层次是上一次的加一
                  Q.push(tmp.to);
              }
          }
      }
      return vis[t];
   }
   int Dfs(int node,int a)
   {

       if(node == t||a == 0)//如果搜到了汇点或者分配到当前节点的流量为零, 返回
        return a;
       int flow =  0,f;
       for(int &i = cur[node];i < G[node].size();++i)//注意用的是引用
       {
          Edge &tmp = edges[G[node][i]];//同样也是引用
          if(d[tmp.to]==d[node]+1&&(f = Dfs(tmp.to,min(a,tmp.cap-tmp.flow)))>0)
          {
              flow += f;
              tmp.flow += f;
              edges[G[node][i]^1].flow -= f;//修改路径
              a -= f;
              if(a==0)
                break;
          }
       }
       return flow;
   }
   int MaxFlow(int s,int t)
   {
       this->s = s;
       this->t = t;
       int flow = 0;
       while(Bfs())
       {
           me(cur);
           flow += Dfs(s,maxn);
       }
       return flow;

   }


};
Dinic dinic;

int p[LEN];
int e[LEN];
int s[LEN];
int main()
{
    int N,M,S,T;
    int t,kase = 0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&N,&M);
        S = 0, T = 1000;//源点设为零, 汇点设为一千
        dinic.init(1000+10);
// int u,v,w;
        int sum = 0;
        for(int i = 0;i < N;++i)
        {
            scanf("%d %d %d",&p[i],&s[i],&e[i]);
            sum += p[i];
        }
        for(int i = 1;i <= 500; ++i)
        {
            dinic.Add(i,T,M);//在每一天到汇点之间建立边
        }
        for(int i = 0;i < N; ++i)
        {
            dinic.Add(S,501+i,p[i]);//在源点到各个人物之间建立边
            for(int j = s[i];j <= e[i];++j)
            {
                dinic.Add(501+i,j,1);//在各任务时间内每一天与与该任务建立边
            }
        }
        int ans = 0;
        ans = dinic.MaxFlow(S,T);
        if(ans == sum)
            printf("Case %d: Yes\n",++kase);
        else
            printf("Case %d: No\n",++kase);
// if(t)
         printf("\n");

    }



    return 0;
}