HDU2883 kebab (压缩区间+网络流)

如今,几乎每个人都喜欢烤肉串(这里的烤肉串是指在一根细长的棍子上烤的肉块)。但是,您在享用美味的食物时,是否考虑过烤肉烤的困难?好吧,这是一个机会,可以帮助您帮助可怜的焙烧炉确保他是否可以处理以下订单而不会令客户不满意。

现在有N个客户到来。客户i将在时间si到达(这意味着焙烧炉无法在时间si之前为客户i服务)。他/她将订购ni个烤肉串,每个烤肉串都需要总共ti单位时间才能得到很好的烤制,并希望在时间ei之前得到它们(恰好在ei的时间也可以)。烧烤炉有一个很大的烧烤炉,可以盛放无限量的烤肉串(真是难以置信,是吧!这是真的!)。但是他的木炭很少,最多只能同时烤M个烤肉串。他足够熟练,无需花费任何时间就可以烤制烤肉串。您可以帮助他确定他是否可以满足所有客户的需求吗?

哦,我忘了说烘烤机不需要连续烤一个烤肉串。这意味着他可以将整个ti单位时间划分为k(1 <= k <= ti)个部分,这样,相邻的两个部分就不必在时间上连续。他还可以将单个烤肉串分成k(1 <= k <= ti)个部分,并同时进行烘烤。烤羊肉串的一部分所需的时间与其所含的肉量成线性关系。因此,如果烤肉串需要10个单位时间才能很好地烤制,他可以将其分成10个部分,并仅用一个单位时间同时烤制。但是请记住,单个单位时间是不可分割的,烤肉串只能分为各个部分,每个部分都需要一个完整的单位时间来烘烤。
输入值
有多个测试用例。每种情况的第一行都包含两个正整数N和M。N是客户数量,M是烧烤炉可以同时烧烤的最大烤肉串。然后,沿着N行描述每位客户,每行描述四个整数:si(到达时间),ni(烤肉串需求),ei(截止日期)和ti(烘烤一个烤肉串所需的时间)。

每个输入块后面都有一个空白行。

限制:
1 <= N <= 200,1 <= M <= 1,000
1 <= ni,ti <= 50
1 <= si <ei <= 1,000,000
输出量
如果焙烧炉可以满足所有客户的需求,则输出“是”(不带引号)。否则,输出“否”。

区间长度太大,如果直接根据区间建边会导致超时,考虑对区间的端点进行离散化,然后对离散化后的区间增加单边的容量,时间复杂度合理。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+100;
const int inf=1e9;

struct node {
    int u,v,w,nxt;
}edge[maxn<<1];
int head[maxn],tot;
void addedge (int u,int v,int w) {
    edge[tot].u=u;
    edge[tot].v=v;
    edge[tot].w=w;
    edge[tot].nxt=head[u];
    head[u]=tot++;
    
    edge[tot].u=v;
    edge[tot].v=u;
    edge[tot].w=0;
    edge[tot].nxt=head[v];
    head[v]=tot++;
} 

int dep[maxn],inq[maxn],cur[maxn],wjm,maxflow,s,t;
bool bfs () {
    for (int i=0;i<=t;i++) {
        cur[i]=head[i];
        dep[i]=inf;
        inq[i]=0;
    }
    dep[s]=0;
    queue<int> q;
    q.push(s);
    while (q.size()) {
        int u=q.front();
        q.pop();
        inq[u]=0;
        for (int i=head[u];i!=-1;i=edge[i].nxt) {
            int v=edge[i].v;
            if (dep[v]>dep[u]+1&&edge[i].w) {
                dep[v]=dep[u]+1;
                if (inq[v]==0) {
                    q.push(v);
                    inq[v]=1;
                }
            }
        }
    }
    if (dep[t]!=inf) return 1;
    return 0;
}

int dfs (int u,int flow) {
    int increase=0;
    if (u==t) {
        wjm=1;
        maxflow+=flow;
        return flow;
    }
    int used=0;
    for (int i=cur[u];i!=-1;i=edge[i].nxt) {
        cur[u]=i;
        int v=edge[i].v;
        if (edge[i].w&&dep[v]==dep[u]+1) {
            if (increase=dfs(v,min(flow-used,edge[i].w))) {
                used+=increase;
                edge[i].w-=increase;
                edge[i^1].w+=increase;
                if (used==flow) break;
            }
        } 
    }
    return used;
} 

int Dinic () {
    while (bfs()) {
        wjm=1;
        while (wjm==1) {
            wjm=0;
            dfs(s,inf);
        }
    }
    return maxflow;
}
int nn[maxn],tt[maxn],ss[maxn],ee[maxn];
int ls[maxn];//离散化数组 
int n,mm,m;
int main () {
//    源点为0
//    1~n为客户
//    n+1~n+m为离散化的时间点
//    n+m+1为汇点
//    源点向每个人连一条nn(i)*tt(i)的边
//    每个人向离散化的时间点连一条容量为inf的边
//    每个时间点向汇点连一条容量为mm的边
//    最后判断最大流是否流满 
    while (~scanf("%d%d",&n,&mm)) {
        int cnt=0;
        for (int i=1;i<=n;i++) scanf("%d%d%d%d",ss+i,nn+i,ee+i,tt+i),ls[++cnt]=ss[i],ls[++cnt]=ee[i];
        sort(ls+1,ls+1+cnt);
        m=unique(ls+1,ls+1+cnt)-ls-1;
        s=0;t=n+m+1;
        for (int i=0;i<=t;i++) head[i]=-1;tot=0;maxflow=0;
        int sum=0;
        for (int i=1;i<=n;i++) {
            addedge(s,i,nn[i]*tt[i]);
            sum+=nn[i]*tt[i];
            for (int j=1;j<=m;j++) {
                if (ss[i]<=ls[j-1]&&ls[j]<=ee[i]) addedge(i,n+j,inf);
            }
        }
        for (int i=1;i<=m;i++) addedge(n+i,t,(ls[i]-ls[i-1])*mm);
        if (Dinic()==sum)
            printf("Yes\n");
        else
            printf("No\n"); 
        
    }
}

 

posted @ 2020-11-24 13:19  zlc0405  阅读(67)  评论(0编辑  收藏  举报