zoukankan      html  css  js  c++  java
  • HDU2883 kebab(最大流判断满流 + 离散化 + 区间化点)

    【题意】:

    有一个烤箱,烤箱在一个时刻最多考M个肉串,N个顾客,每个顾客有属性s,n,e,t s是来的时间,n是想要的肉串数量,e是最晚离开的时间,t是烤的时间(几分熟)。

    顾客的烤肉可以分开烤,比如一串烤肉烤的时间是t,那么分成t分就可以在1的时间内烤完。问能否满足所有的顾客。

    很像HDU3527

    【思路】:

    以时间作为流

    每个单位时间只能烤M个肉,那么如果一个顾客的属性为s, n, e, t,那么如果满足n*t <= (t-s)*M则这个顾客是可以被满足的。

    那么问题可以转换成区间覆盖问题:线段上每个单位容量为M,每个顾客的区间为[s, e],顾客容量为n*t,问能否覆盖完全。

    【建图】:

    类似HDU3527

    设立超级源点sp = 0,sp向每个顾客i连边,权重为n*t,每个单位时间向超级汇点tp连边,权重为M,顾客向时间点连边,权重为 inf,跑最大流即可。

    !!但是注意到s,e的范围是1e6那么这样直接连边的话内存需要1e8,肯定会MLE,所以要进行离散化。

    【离散化】:

    使用C++ STL unique( array.begin(), array.end() )函数,将时间点s,e进行排序去重,最多可以获得2*N个时间点,2*N-1个区间,遍历每个时间区间j, [l ,r]时

    遍历每个顾客i的时间[s, e]如果s<=l && e>=r 则i->j连边,权重为inf。

    最后跑最大流,判断是否满流即可。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 200 + 5;
    const int maxm = 1e6 + 5;
    const int inf = 0x3f3f3f3f;
    int n, m, sp, tp, sum, maxflow;
    int s[maxn], e[maxn], Time[maxn<<1], d[maxn*3];
    int head[maxn*3], tot;
    struct edge{
        int to, w, next;
    } ed[maxm<<1];
    inline void init(){
        sum = sp = 0;
        tot = 1;
        memset( head ,-1, sizeof(head) );
    }
    
    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[sp] = 1;
        q.push(sp);
        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==tp ) return 1;
                }
            }
        }
        return 0;
    }
    
    inline int dfs( int x, int flow ){
        if( x==tp ) 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(ed[i].w, res) );
                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( sp, inf ) ) maxflow += flow;
        }
    }
    
    int main(){
        // freopen("in.txt", "r", stdin);
        while( ~scanf("%d%d", &n, &m) ){
            init();
            int cnt = 1;
            int num, t;
            for( int i=1; i<=n; i++ ){
                scanf("%d%d%d%d", &s[i], &num, &e[i], &t);
                add( sp, i, num*t);
                sum += num*t;
                Time[cnt++] = s[i];
                Time[cnt++] = e[i];
            }
            sort( Time+1, Time+cnt+1 );
            int top = unique(Time+1, Time+cnt+1)-(Time+1);
            tp = n+top+1;
            for( int i=1; i<=top; i++ ){
                add( n+i, tp, m*(Time[i]-Time[i-1]) );      //时间区间编号i需要映射到i+n,避免与顾客的编号重复
                for( int j=1; j<=n; j++ ){
                    if( s[j]<=Time[i-1] && e[j]>=Time[i] ) add( j, n+i, inf );
                }
            }
            dinic();
            if( maxflow==sum ) puts("Yes");
            else puts("No");
        }
    
        return 0;
    }
  • 相关阅读:
    书写神器——markdown
    数据大作战
    Laraveladmin自定义拓展及常见问题(下)
    Laraveladmin自定义拓展及常见问题(上)
    打造网页版聊天页面的几个知识点
    说说windows系统的事儿
    《软件开发者路线路》读后感
    如何优雅的仿站Step One——扒网站篇
    SQLSERVER 独占锁 独占模式
    解决vs2010调试很慢的方法
  • 原文地址:https://www.cnblogs.com/WAautomaton/p/11004948.html
Copyright © 2011-2022 走看看