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;
}
原文地址:https://www.cnblogs.com/WAautomaton/p/11004948.html