zoukankan      html  css  js  c++  java
  • HDU 3572 Task Schedule(拆点+最大流dinic)

    Task Schedule

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 7753    Accepted Submission(s): 2381

    Problem Description
    Our geometry princess XMM has stoped her study in computational geometry to concentrate on her newly opened factory. Her factory has introduced M new machines in order to process the coming N tasks. For the i-th task, the factory has to start processing it at or after day Si, process it for Pi days, and finish the task before or at day Ei. A machine can only work on one task at a time, and each task can be processed by at most one machine at a time. However, a task can be interrupted and processed on different machines on different days. 
    Now she wonders whether he has a feasible schedule to finish all the tasks in time. She turns to you for help.
     
    Input
    On the first line comes an integer T(T<=20), indicating the number of test cases.

    You are given two integer N(N<=500) and M(M<=200) on the first line of each test case. Then on each of next N lines are three integers Pi, Si and Ei (1<=Pi, Si, Ei<=500), which have the meaning described in the description. It is guaranteed that in a feasible schedule every task that can be finished will be done before or at its end day.
     
    Output
    For each test case, print “Case x: ” first, where x is the case number. If there exists a feasible schedule to finish all the tasks, print “Yes”, otherwise print “No”.

    Print a blank line after each test case.
     
    Sample Input
    2
    4 3
    1 3 5
    1 1 4
    2 3 7
    3 5 9
     
    2 2
    2 1 3
    1 2 2
     
    Sample Output
    Case 1: Yes
    Case 2: Yes
     

    题目链接:HDU 3572

    拆点的最大流判断是否满流的题目,点怎么拆呢?从源点S连向每一个任务i一条容量为p的边,说明每一个任务一开始要p个流量流入,然后每一个任务i向时间点[s,e]连一条容量为1的边,说明一个任务只能同时在一个时间点被工作,即不能同时既在时间点A上加工又在时间点B上加工,然后每一个时间点向T连一条容量为m个边,说明一个时间点只能最多同时有m个机器在工作。最后你就是要判断从S流出的$n*p$个流量能否全部流入T中就好了

    空间复杂度大概是$(500+500^2+500)*2$条边,$500+500$个点,原本只会最辣鸡的FF想低空卡过这题,然而被无限TLE教做人,查查题解又膜膜dinic,发现dinic也容易理解,分层的意义就是减少没有用的搜索,因为增广一定是从最小距离距离近的到最小距离远的,那么那些d[v]!=d[u]+1的点就可以被忽略掉了

    代码:

    #include <stdio.h>
    #include <bits/stdc++.h>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define CLR(arr,val) memset(arr,val,sizeof(arr))
    #define LC(x) (x<<1)
    #define RC(x) ((x<<1)+1)
    #define MID(x,y) ((x+y)>>1)
    typedef pair<int,int> pii;
    typedef long long LL;
    const double PI=acos(-1.0);
    const int N=1010;
    const int M=251000+7;
    struct edge
    {
        int to,nxt;
        int cap;
    };
    edge E[M<<1];
    int head[N],tot,d[N];
    
    void add(int s,int t,int cap)
    {
        E[tot].to=t;
        E[tot].cap=cap;
        E[tot].nxt=head[s];
        head[s]=tot++;
    
        E[tot].to=s;
        E[tot].cap=0;
        E[tot].nxt=head[t];
        head[t]=tot++;
    }
    void init()
    {
        CLR(head,-1);
        tot=0;
    }
    int bfs(int s,int t)
    {
        CLR(d,-1);
        d[s]=0;
        queue<int>Q;
        Q.push(s);
        while (!Q.empty())
        {
            int now=Q.front();
            Q.pop();
            for (int i=head[now]; ~i; i=E[i].nxt)
            {
                int v=E[i].to;
                if(d[v]==-1&&E[i].cap>0)
                {
                    d[v]=d[now]+1;
                    if(v==t)
                        return 1;
                    Q.push(v);
                }
            }
        }
        return d[t]!=-1;
    }
    int dfs(int s,int t,int f)
    {
        if(s==t||!f)
            return f;
        int r=0;
        for (int i=head[s]; ~i; i=E[i].nxt)
        {
            int v=E[i].to;
            if(d[v]==d[s]+1&&E[i].cap)
            {
                int d=dfs(v,t,min(f,E[i].cap));
                if(d>0)
                {
                    E[i].cap-=d;
                    E[i^1].cap+=d;
                    r+=d;
                    f-=d;
                    if(!f)
                        break;
                }
            }
        }
        if(!r)
            d[s]=INF;
        return r;
    }
    int dinic(int s,int t)
    {
        int r=0;
        while (bfs(s,t))
            r+=dfs(s,t,INF);
        return r;
    }
    int main(void)
    {
        int tcase,p,s,e,i,j,n,m;
        scanf("%d",&tcase);
        for (int q=1; q<=tcase; ++q)
        {
            init();
            scanf("%d%d",&n,&m);
            int S=0;
            int tl=INF,tr=-INF;
            int sump=0;
            for (i=1; i<=n; ++i)
            {
                scanf("%d%d%d",&p,&s,&e);
                add(S,i,p);
                sump+=p;
    
                if(s<tl)
                    tl=s;
                if(e>tr)
                    tr=e;
    
                for (j=s; j<=e; ++j)
                    add(i,n+j,1);
            }
            int T=n+tr+1;
            for (i=tl; i<=tr; ++i)
                add(n+i,T,m);
            printf("Case %d: %s
    
    ",q,dinic(S,T)==sump?"Yes":"No");
        }
        return 0;
    }
  • 相关阅读:
    无法重用Linq2Entity Query
    The Joel Test
    MSBuilder directly instead of default VSComplie with keyborad shotcut 原创
    客户端缓存(Client Cache)
    关于代码重构和UT的一些想法,求砖头
    ExtJS2.0实用简明教程 应用ExtJS
    Perl information,doc,module document and FAQ.
    使用 ConTest 进行多线程单元测试 为什么并行测试很困难以及如何使用 ConTest 辅助测试
    史上最简单的Hibernate入门简介
    汽车常识全面介绍 传动系统
  • 原文地址:https://www.cnblogs.com/Blackops/p/6155319.html
Copyright © 2011-2022 走看看