hdu2883 kebab (最大流+离散化)

题目大意:
你在经营一个烤肉店,给你n个客人,每个客人都要求有ni的肉串,并且不要客人要求的肉串的一串烤制时间是不一样的(为ti),客人将在si到,并且在ei的时候走。你有一个烤肉机,每天可以烤制m个串,并且每个串是可以分不连续的几天烤制。

提交地址:
HDU 2883 kebab

题解:
从数据规模和模型很容易看出来是一道网络流的题目,hdu上还有一道弱化版的,是将每一天分作一个点来,但是这题的si,ei有百万规模,不论用哪种网络流算法都是会超时的,所以要把时间按段做点。

/*
ID: Rec
PROG: test
LANG: C++
*/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<algorithm>
#include<stack>
#define MOD 29999
#define INF 0x5f5f5f5f
struct aa{
    int p,op,next,f;
}da[MOD*10];
int n,m,S,T,cum;
int tou[MOD*2],dd,dist[MOD*2],cnt[MOD*2],ans,time[MOD*10];
int s[MOD],e[MOD];
void add(int x,int y,int f){
    da[++dd].p=y;da[dd].next=tou[x];tou[x]=dd;da[dd].op=dd+1;da[dd].f=f;
    da[++dd].p=x;da[dd].next=tou[y];tou[y]=dd;da[dd].op=dd-1;da[dd].f=0;
}
bool cmp(int x,int y){return x<y;}
int sap(int x,int delta){
    if (x==T)return delta;
    int sum=0;int mindis=T;
    for (int i=tou[x];i;i=da[i].next){
        int v=da[i].p;
        if (da[i].f&&dist[x]==dist[v]+1){
            int save=sap(v,std::min(delta-sum,da[i].f));
            da[i].f-=save;
            sum+=save;
            da[da[i].op].f+=save;
            if (dist[S]>T || sum==delta) return sum;
        }
        if (da[i].f)mindis=std::min(mindis,dist[v]);
    }
    if (sum==0){
        if (--cnt[dist[x]]==0)dist[S]=T+1;
        else ++cnt[dist[x]=mindis+1];
    }
    return sum;
}
int main(){
    freopen("hdu2883.in","r",stdin);
    freopen("hdu2883.out","w",stdout);
    while (scanf("%d%d",&n,&m)!=EOF){
        cum=0;
        memset(tou,0,sizeof(tou));
        memset(dist,0,sizeof(dist));
        memset(cnt,0,sizeof(cnt));
        dd=0;
        ans=0;S=0;int tot=0;
        for (int i=1;i<=n;i++){
            int ti,ni;
            scanf("%d%d%d%d",&s[i],&ni,&e[i],&ti);
            ans+=ni*ti;
            time[++tot]=s[i];time[++tot]=e[i];
            add(S,i,ni*ti);
        }
        std::sort(time+1,time+tot+1,cmp);
        int c=1;
        for (int i=1;i<=tot;i++)
            if (time[c]!=time[i])time[++c]=time[i];
        T=c+n+1;
        for (int i=1;i<=c;i++){
            add(n+i,T,m*(time[i]-time[i-1]));
            for (int j=1;j<=n;j++)
                if (s[j]<=time[i-1]&&time[i]<=e[j])add(j,i+n,INF);
        }
        while (dist[S]<=T)ans-=sap(S,INF);
        if (ans==0)printf("Yes\n");else printf("No\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值