zoukankan      html  css  js  c++  java
  • HDU3572 Task Schedule(最大流+构图思维)

    题意:

    有N个任务M个机器,给每个任务i完成所花费的时间Pi且每个任务要在第Si天后开始,在第Ei天前结束,保证任务在(S,E)之间一定能完成。

    每个机器在一天里只能运行一个任务,一个任务可以在中途更换机器继续执行,问有没有一种安排时间的方式使得全部任务都完成。

    (第一时间看不出来是最大流啊!!)

    思路:

    分析之后可以这样想,设立一个超级源点S=0,让S与每个任务i建立双向边S->i,权重为Pi,然后让每个任务向每一天d(d就是Si到Ei的每一天)

    建立双向边i->d,权重是1(因为每个机器一天只能运行1个任务),然后让每一天d向一个超级汇点T建立双向边d->T,权重为M(因为从任务开

    始到所有任务完成,这一天d最多会有M个机器运转,也就是说最多有M个任务在进行着)。然后跑最大流,如果最大流maxflow和sigma(Pi)相同,

    那么输出“Yes”,else输出“No”。

    !!!值得注意的是,要把任务i和天数d当做二分图,(因为可能任务i和任务j可能会连接一条边,因为所有[Si, Ei]区间一定有可能包含任务下标)

    那就意味着要把任务序号或者天数序号进行映射,我的代码是把天数d映射到了d+n。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 500 + 5;
    const int inf = 0x3f3f3f3f;     //INF
    const int ainf = 0xcfcfcfcf;    //-INF
    int n, m, T, d[maxn*2], s, t, maxflow;
    int head[maxn*2], tot, sum;
    struct edge{
        int to, w, next;
    } ed[maxn*maxn*2+maxn*4];
    //边的个数 = 任务节点的到天数节点连边上界为n*n,双向乘2 + 超级源点与任务节点连双向边 + 超级汇点与天数节点连双向边。
    inline void add( int u, int v, int w ){
        ed[++tot].to = v; ed[tot].w = w; ed[tot].next = head[u]; head[u] = tot;
        ed[++tot].to = u; ed[tot].w = 0; ed[tot].next = head[v]; head[v] = tot;
    }
    
    inline bool bfs(){
        queue<int> q;
        memset( d, 0, sizeof(d) );
        d[s] = 1;
        q.push(s);
        while( !q.empty() ){
            int x = q.front();
            q.pop();
            for( int i=head[x]; i!=-1; i=ed[i].next ){
                int y = ed[i].to;
                if( ed[i].w && !d[y] ){
                    d[y] = d[x] + 1;
                    q.push(y);
                    if( y==t ) return 1;
                }
            }
        }
        return 0;
    }
    
    inline int min( int a, int b ){
        return a<b ?a:b;
    }
    
    inline int max( int a, int b ){
        return a>b? a:b;
    }
    
    inline int dfs( int x, int flow ){
        if(x==t) return flow;
        int res = flow, k;
        for( int i=head[x]; i!=-1 && res; i=ed[i].next ){
            int y = ed[i].to;
            if( ed[i].w && d[y]==d[x]+1 ){
                k = dfs(y, min(res, ed[i].w) );
                if(!k) d[y] = 0;
                ed[i].w -= k;
                ed[i^1].w += k;
                res -= k;
            }
        }
        return flow-res;
    }
    
    inline void dinic(){
        int flow = maxflow = 0;
        while( bfs() )
            while( flow=dfs(s, inf) ) maxflow += flow;
    }
    
    int main(){
        // freopen("in.txt", "r", stdin);
        scanf("%d", &T);
        for( int k=1; k<=T; k++ ){
            memset( head, -1, sizeof(head) );
            tot = 1; sum = 0;
            scanf("%d%d", &n, &m);
            s = 0;
            int l = inf, r = ainf;          //ainf==0xcfcfcfcf 即-INF
            for( int i=1; i<=n; i++ ){
                int a, b, p;
                scanf("%d%d%d", &p, &a, &b);
                l = min( a, l );            //找到天数的下界
                r = max( b, r );            //找到天数的上界
                add( s, i, p );             //超级源点与任务i连边
                for( int  j=a; j<=b; j++ ) add( i, j+n, 1 );        //任务与映射过得天数序号连边
                sum += p;           //sigma(Pi)
            }
            t = r+n+1;              //超级汇点,也可以让t普遍选择为2*maxn-1,没啥区别的
            for( int i=l; i<=r; i++ ) add( i+n, t, m );     //天数向超级汇点t连边
            dinic();
            printf("Case %d: ", k);
            if( maxflow==sum ) puts("Yes
    ");       //puts()自带换行,再加一个
    来控制输出格式
            else puts("No
    ");
        }
    
        return 0;
    }
  • 相关阅读:
    父组件和子组件之间的生命周期执行顺序
    Vue生命周期四个阶段
    Vue watch监听
    Vue computed计算属性 理解
    Vue中v-if 与 v-show的区别
    虚拟DOM
    MVC与MVVM原理
    单例模式 回流与重绘
    判断某个对象属于哪种数据类型
    原生JS的兼容性问题
  • 原文地址:https://www.cnblogs.com/WAautomaton/p/10974429.html
Copyright © 2011-2022 走看看