HDU 3572 Task Schedule 网络流建图

1.题意:工厂里有n个任务,每个任务都有最早开始时间si,完成所需时间pi,最晚结束时间ei;现在工厂里有m台机器,每台机器每次只能执行一个任务,每个任务可以在执行过程中中断然后放到另一台机器上执行。问这些任务能否在期限内完成。

2.分析:完成所有的任务所需时间为 Sum(pi),如果我们最大能力的去让机器处理可处理的任务,那么机器处理的总时间也就是处理所有任务最大化的时间,如果这个时间>=Sum(pi),那么我们的任务也就都能完成,否则无法都完成。

那么怎么求出这个最大化的时间呢?这里需要构建一个网络流最大流模型。

每个任务看作一个源点,该任务与每一个能执行该任务的天建一条边,容量为1,因为每一天每一台机器只能执行一个任务。然后建立一个超级汇点,连接每一个天,容量为m,因为每一天最多处理m个任务,贡献m的时间。最后多个源点当然要建立一个超级源点!连接每一个任务,容量为该任务所需的时间。对于这个图跑最大流,判断即可。

注:一定要用Dinic 的当前弧优化,否则超时QAQ~

3.代码:

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define INF 1e18
typedef long long LL;
const int maxnM = 502000 + 7;
const int maxnN = 1100;
struct Edge{
    int to,next;
    LL cap,flow;
}edge[maxnM];
int n,m,tot,head[maxnN],dist[maxnN],cur[maxnN];
int vis[507];
void addEdge(int a,int b,LL c){
    edge[tot].to = b;edge[tot].cap = c;edge[tot].flow = 0;edge[tot].next = head[a];head[a] = tot++;
    edge[tot].to = a;edge[tot].cap = 0;edge[tot].flow = 0;edge[tot].next = head[b];head[b] = tot++;
}
bool BFS(int s,int t){
    memset(dist,0,sizeof(dist));
    dist[s] = 1;
    queue<int> que;
    que.push(s);
    while(!que.empty()){
        int u = que.front();
        que.pop();
        for(int i = head[u];~i;i = edge[i].next){
            int v = edge[i].to;
            if(!dist[v]&&edge[i].cap > edge[i].flow){
                dist[v] = dist[u] + 1;
                que.push(v);
            }
        }
    }
    if(dist[t] > 0)return true;
    return false;
}
LL DFS(int p,int t,LL nowFlow){
     if(p==t||nowFlow==0)return nowFlow;
     LL minFlow = 0;
     for(int &i = cur[p];~i;i = edge[i].next){
        int v = edge[i].to;
        if(dist[v] == dist[p] + 1&&edge[i].cap >edge[i].flow){
            LL f = DFS(v,t,min(nowFlow,edge[i].cap - edge[i].flow));
            if(f==0)continue;
            edge[i].flow+=f;
            edge[i^1].flow-=f;
            minFlow+=f;
            nowFlow-=f;
            if(nowFlow==0)break;
        }
     }
     return minFlow;
}
LL Dinic(int s,int t){
     LL flow = 0;
     while(BFS(s,t)){
         for(int i = s;i<=t;i++)cur[i] = head[i];//当前弧优化!!!
         LL res = DFS(s,t,INF);
         flow+=res;
     }
     return flow;
}
int main()
{
    int T;
    scanf("%d",&T);
    int t = 0;
    while(T--){
        t++;
        tot = 0;
        LL sum = 0;
        memset(head,-1,sizeof(head));
        memset(vis,0,sizeof(vis));
        scanf("%d%d",&n,&m);
        int cnt = n+1;
        for(int i = 1;i<=n;i++){
            int p,s,e;
            scanf("%d%d%d",&p,&s,&e);
            sum+=p;
            addEdge(0,i,(LL)p);//超级源点与每一个任务建边
            for(int j = s;j<=e;j++){
                if(!vis[j]){
                    vis[j] = cnt++;//给出现的天一个编号
                }
                addEdge(i,vis[j],1);//任务i与每一天建边
            }
        }
        for(int i = n+1;i<=cnt-1;i++){
            addEdge(i,cnt,(LL)m);//每一天与超级汇点建边
        }
        LL ans = Dinic(0,cnt);
        if(ans==sum)printf("Case %d: Yes\n\n",t);
        else printf("Case %d: No\n\n",t);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40772692/article/details/83269682