HDU_2883_kebab(最大流)

kebab

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1291    Accepted Submission(s): 542



Problem Description
Almost everyone likes kebabs nowadays (Here a kebab means pieces of meat grilled on a long thin stick). Have you, however, considered about the hardship of a kebab roaster while enjoying the delicious food? Well, here's a chance for you to help the poor roaster make sure whether he can deal with the following orders without dissatisfying the customers.

Now N customers is coming. Customer i will arrive at time si (which means the roaster cannot serve customer i until time si). He/She will order ni kebabs, each one of which requires a total amount of ti unit time to get it well-roasted, and want to get them before time ei(Just at exactly time ei is also OK). The roaster has a big grill which can hold an unlimited amount of kebabs (Unbelievable huh? Trust me, it’s real!). But he has so little charcoal that at most M kebabs can be roasted at the same time. He is skillful enough to take no time changing the kebabs being roasted. Can you help him determine if he can meet all the customers’ demand?

Oh, I forgot to say that the roaster needs not to roast a single kebab in a successive period of time. That means he can divide the whole ti unit time into k (1<=k<=ti) parts such that any two adjacent parts don’t have to be successive in time. He can also divide a single kebab into k (1<=k<=ti) parts and roast them simultaneously. The time needed to roast one part of the kebab well is linear to the amount of meat it contains. So if a kebab needs 10 unit time to roast well, he can divide it into 10 parts and roast them simultaneously just one unit time. Remember, however, a single unit time is indivisible and the kebab can only be divided into such parts that each needs an integral unit time to roast well.
 

Input
There are multiple test cases. The first line of each case contains two positive integers N and M. N is the number of customers and M is the maximum kebabs the grill can roast at the same time. Then follow N lines each describing one customer, containing four integers: si (arrival time), ni (demand for kebabs), ei (deadline) and ti (time needed for roasting one kebab well).

There is a blank line after each input block.

Restriction:
1 <= N <= 200, 1 <= M <= 1,000
1 <= ni, ti <= 50
1 <= si < ei <= 1,000,000
 

Output
If the roaster can satisfy all the customers, output “Yes” (without quotes). Otherwise, output “No”.
 

Sample Input
  
  
2 10 1 10 6 3 2 10 4 2 2 10 1 10 5 3 2 10 4 2
 

Sample Output
  
  
Yes No
 题意:有一个烧烤机,每次最多能烤 m 块肉,现在有 n 个人来买烤肉,每个人到达时间为 si,离开时间为 ei,烤肉数量为 ni,烤肉所需烘烤时间为 ti,每个人要烤的肉可以分成若干份在同时烤,问是否存在一种方案可以满足所有顾客的需求。

分析:刚开始拿到这题,又傻乎乎地直接网络流去搞了。不用说TLE都没到就先MLE了。然后想了很久的如何建图。还是没想出来,网络流模型建图方面还是太弱了,太弱了。后来还是看了别人的才知道如何构建模型的。一定要加强网络流建模的锻炼。

建图:把所有人到达的时间以及离开的时间存在一个数组里,然后sort一下,那么相当于将这些时间段从小到大重新分成了n-1段。接下来,对于一个人来说,如果一个新的时间段([Sj,Ej])在这个人的时间段内,那么从这个人指向这个新的时间段,容量为INF;加入超级源点s,s指向每一个人,容量为 n[i] * t[i];加入超级汇点t,使得所有的新时间段都指向t,容量为(Ej - Sj) * M。

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2883
代码清单:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<cctype>
#include<string>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;

#define end() return 0

typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;

const int maxn = 1000 + 5;
const int INF = 0x7f7f7f7f;

struct Edge{
    int from,to,cap,flow;
    Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};

struct dinic{
    int n,m,s,t; //结点数,边数(包括反向弧),源点,汇点
    vector<Edge>edge;//边表。edge[e]和edge[e^1]互为反向弧
    vector<int>G[maxn];//邻接表。G[i][j]表示结点i的第j条边在e数组的序号
    bool vis[maxn]; //bfs用
    int d[maxn]; //从起点到i的距离
    int cur[maxn]; //当前弧下标

    void init(int n,int s,int t){
        this -> n = n;
        this -> s = s;
        this -> t = t;
        for(int i=0;i<=n;i++) G[i].clear();
        edge.clear();
    }

    void addEdge(int from,int to,int cap){
        edge.push_back(Edge(from,to,cap,0));
        edge.push_back(Edge(to,from,0,0));
        m=edge.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }

    bool bfs(){
        memset(vis,false,sizeof(vis));
        queue<int>q;
        q.push(s);
        d[s]=0;
        vis[s]=true;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=0;i<G[x].size();i++){
                Edge& e=edge[G[x][i]];
                if(!vis[e.to]&&e.cap>e.flow){ //只考虑残量网络中的弧
                    vis[e.to]=true;
                    d[e.to]=d[x]+1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    int dfs(int x,int a){
        if(x==t||a==0) return a;
        int flow=0,f;
        for(int& i=cur[x];i<G[x].size();i++){ // & -> 从上次考虑的弧
            Edge& e=edge[G[x][i]];
            if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){
                e.flow+=f;
                edge[G[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a==0) break;
            }
        }
        return flow;
    }

    int maxflow(){
        int flow=0;
        while(bfs()){
            memset(cur,0,sizeof(cur));
            flow+=dfs(s,INF);
        }
        return flow;
    }
};

int N,M;
int maxt;
int sumt;
int tail;
dinic dc;
struct Node{int s,n,e,t;}p[maxn];
int time[maxn],ti;

void input(){
    maxt=-INF;
    sumt=0;
    ti=0;
    for(int i=1;i<=N;i++){
        scanf("%d%d%d%d",&p[i].s,&p[i].n,&p[i].e,&p[i].t);
        maxt=max(maxt,p[i].e);
        sumt+=p[i].t*p[i].n;
        time[ti++]=p[i].s;
        time[ti++]=p[i].e;
    }
}

void createGraph(){
    tail=N+ti+1;
    dc.init(tail+1,0,tail);
    sort(time,time+ti);
    for(int i=1;i<=N;i++){
        dc.addEdge(0,i,p[i].n*p[i].t);
        for(int j=1;j<ti;j++){
            if(p[i].s<=time[j-1]&&time[j]<=p[i].e){
                dc.addEdge(i,N+j,INF);
            }
        }
    }
    for(int i=1;i<ti;i++){
        dc.addEdge(N+i,tail,(time[i]-time[i-1])*M);
    }
}

void solve(){
    createGraph();
    if(dc.maxflow()==sumt) puts("Yes");
    else puts("No");
}
int main(){
    while(scanf("%d%d",&N,&M)!=EOF){
        input();
        solve();
    }
    end();
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值