HDU2883kebab(最大流ISAP)离散化思想建图

kebab

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 1145    Accepted Submission(s): 472

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

Source

2009 Multi-University Training Contest 9 - Host by HIT

题意:有N(<=200)个顾客,第 i 个顾客现要点ni(<=50)个烤串,每个烤串需要花 ti(<=50) 个时间单位 , 服务时间从si(刚开始服务)到ei(包括ei时间点),假设一个串需要烤10个单位的时间,那么可以把这个串分成10个部分,每1部分只要1个单位的时间就可以烤好给顾客。现在烧烤架在同一时间最多可以烤M个串,问能不能服务完所有的顾客?

解析:看了网上解题,用离散化时间来建图。首先可根据题意,把每个顾客所要的ni个串分成 ni*ti 个部分,也就相当于分成ni*ti个串,每个串花1个单位时间。那么现在我们要确定流的是什么,题意中“烧烤架在同一时间最多可以烤M个串”,所以时每个间点与汇点建一条边,容量为M,先不看会不会超时,建立可行方案等会再来优化。确定流的是串的个数时,我们就可以把
 源点 与每个顾客建一条边,边容为分解后串的个数ni*ti,最后每个顾客与服务时间内的每个时间点建一条边,边容为>=ni*ti 即可。建完后,方案是可行的,但时间点可达 100W个点,这样会超时,那么就需要用到离散化了,把每个出现的时间点记下来排序去重后,假设得k(<=400)个不同的时间点,那么就会有k-1个时间段,我们可以把每个时间段看成一个点,那么顾客与要求的时间内的时间段建边时容量可以不变(因为从每个顾客最多只需占用ni*ti 烤串位),而时间段与汇点的容量需要改动一下变为 M*(时间段的长度,不包括时间段的起始点)。
这样就建好了,点的总个数=1+n+(k-1)+1。这样便不会超时了。

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define captype int

const int MAXN = 100010;   //点的总数
const int MAXM = 400010;    //边的总数
const int INF = 1<<30;
struct EDG{
    int to,next;
    captype cap,flow;
} edg[MAXM];
int eid,head[MAXN];
int gap[MAXN];  //每种距离(或可认为是高度)点的个数
int dis[MAXN];  //每个点到终点eNode 的最短距离
int cur[MAXN];  //cur[u] 表示从u点出发可流经 cur[u] 号边

void init(){
    eid=0;
    memset(head,-1,sizeof(head));
}
//有向边 三个参数,无向边4个参数
void addEdg(int u,int v,captype c,captype rc=0){
    edg[eid].to=v; edg[eid].next=head[u];
    edg[eid].cap=c; edg[eid].flow=0; head[u]=eid++;

    edg[eid].to=u; edg[eid].next=head[v];
    edg[eid].cap=rc; edg[eid].flow=0; head[v]=eid++;
}
//预处理eNode点到所有点的最短距离
void BFS(int sNode, int eNode){
    queue<int>q;
    memset(gap,0,sizeof(gap));
    memset(dis,-1,sizeof(dis));
    gap[0]=1;
    dis[eNode]=0;
    q.push(eNode);
    while(!q.empty()){
        int u=q.front(); q.pop();
        for(int i=head[u]; i!=-1; i=edg[i].next){
            int v=edg[i].to;
            if(dis[v]==-1){
                dis[v]=dis[u]+1;
                gap[dis[v]]++;
                q.push(v);
            }
        }
    }
}
int S[MAXN];    //路径栈,存的是边的id号
captype maxFlow_sap(int sNode,int eNode, int n){  //注意:n为点的总个数,包括源点与汇点
    BFS(sNode, eNode);              //预处理eNode到所有点的最短距离
    if(dis[sNode]==-1) return 0;    //源点到不可到达汇点
    memcpy(cur,head,sizeof(head));

    int top=0;  //栈顶
    captype ans=0;  //最大流
    int u=sNode;
    while(dis[sNode]<n){   //判断从sNode点有没有流向下一个相邻的点
        if(u==eNode){   //找到一条可增流的路
            captype Min=INF ;
            int inser;
            for(int i=0; i<top; i++)    //从这条可增流的路找到最多可增的流量Min
            if(Min>edg[S[i]].cap-edg[S[i]].flow){
                Min=edg[S[i]].cap-edg[S[i]].flow;
                inser=i;
            }
            for(int i=0; i<top; i++){
                edg[S[i]].flow+=Min;
                edg[S[i]^1].flow-=Min;  //可回流的边的流量
            }
            ans+=Min;
            top=inser;  //从这条可增流的路中的流量瓶颈 边的上一条边那里是可以再增流的,所以只从断流量瓶颈 边裁断
            u=edg[S[top]^1].to;  //流量瓶颈 边的起始点
            continue;
        }
        bool flag = false;  //判断能否从u点出发可往相邻点流
        int v;
        for(int i=cur[u]; i!=-1; i=edg[i].next){
            v=edg[i].to;
            if(edg[i].cap-edg[i].flow>0 && dis[u]==dis[v]+1){
                flag=true;
                cur[u]=i;
                break;
            }
        }
        if(flag){
            S[top++] = cur[u];  //加入一条边
            u=v;
            continue;
        }
        //如果上面没有找到一个可流的相邻点,则改变出发点u的距离(也可认为是高度)为相邻可流点的最小距离+1
        int Mind= n;
        for(int i=head[u]; i!=-1; i=edg[i].next)
        if(edg[i].cap-edg[i].flow>0 && Mind>dis[edg[i].to]){
            Mind=dis[edg[i].to];
            cur[u]=i;
        }
        gap[dis[u]]--;
        if(gap[dis[u]]==0) return ans;  //当dis[u]这种距离的点没有了,也就不可能从源点出发找到一条增广流路径
                                        //因为汇点到当前点的距离只有一种,那么从源点到汇点必然经过当前点,然而当前点又没能找到可流向的点,那么必然断流
        dis[u]=Mind+1;      //如果找到一个可流的相邻点,则距离为相邻点距离+1,如果找不到,则为n+1
        gap[dis[u]]++;
        if(u!=sNode) u=edg[S[--top]^1].to;  //退一条边

    }
    return ans;
}

int findlocat(int *tm,int tn,int ti){
    int l=0 , r=tn-1 , mid;
    while(l<=r){
        mid=(l+r)>>1;
        if(ti==tm[mid])return mid;
        if(ti>tm[mid]) l=mid+1;
        else r=mid-1;
    }
    return 0;
}

struct MAN{
    int sTime,eTime,kPart ;
}man[205];

int main(){
    int n,m , ni,ti;
    int s , t , ans;
    int time1[405],k;
    while(scanf("%d%d",&n,&m)>0){
        k=0; s=0; ans=0;
        init();

        for(int i=1; i<=n; i++){
            scanf("%d%d%d%d",&man[i].sTime,&ni,&man[i].eTime,&ti);

            man[i].kPart = ni*ti;
            ans += ni*ti;
            time1[k++]=man[i].sTime;
            time1[k++]=man[i].eTime;

            addEdg(s , i , ni*ti);
        }
        sort(time1,time1+k);
        int j=0;
        for(int i=1; i<k; i++)
            if(time1[j]!=time1[i])
            time1[++j]=time1[i];
        k=j+1;
        t=n+j+1;

        for( j=1; j<k; j++)
            addEdg(j+n , t , m*(time1[j]-time1[j-1]));

        for(int u=1; u<=n; u++){
            j=findlocat(time1 , k , man[u].sTime)+1;
            while(time1[j]<=man[u].eTime&&j<k){
                addEdg(u , j+n , man[u].kPart);
                j++;
            }
        }

        ans-=maxFlow_sap(s, t , t+1);
        printf("%s\n",ans>0?"No":"Yes");
    }
}
时间: 2024-11-05 07:00:34

HDU2883kebab(最大流ISAP)离散化思想建图的相关文章

HDU3572Task Schedule(最大流 ISAP比较快)建图方法不错

Task Schedule Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5007    Accepted Submission(s): 1636 Problem Description Our geometry princess XMM has stoped her study in computational geometry t

hdu 3572 仪器与任务 最大流 好题 体会建图思想

Task Schedule Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6802    Accepted Submission(s): 2124 Problem Description Our geometry princess XMM has stoped her study in computational geometry to

Random Maze (hdu 4067 最小费用流 好题 贪心思想建图)

Random Maze Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1373    Accepted Submission(s): 514 Problem Description In the game "A Chinese Ghost Story", there are many random mazes which

BZOJ 3218 A+B Problem(最大流 + 主席树优化建图)

题目:A+B Problem 感谢 Nietzsche 在省选紧迫之际花 39' 给我讲这道题. 这题我并没有想出来,感觉又浪费一道好题了. 需要用最小割,建模方式如下(假设若 2 取黑色,1 取白色会使 2 为奇怪方格): 跑一边最大流,求出最小割,用所有的 W + 所有的 B - 最小割,就是答案. 不过,对于每一个结点 2,在寻找像 1 这样(li <= aj <= ri)的结点时,总不能一个一个枚举吧? O(n2) T 飞. 所以,需要用主席树优化一下.线段树优化建图笔记. 代码未完待

poj1149 PIGS 最大流(神奇的建图)

一开始不看题解,建图出错了.后来发现是题目理解错了.  if Mirko wants, he can redistribute the remaining pigs across the unlocked pig-houses. 题目中的这句话非常关键,没理解就错掉了.有很多人写的题解只告诉我们怎么做,却没告诉我们为什么要那样做. 这句话是的意思是可以重组打开过的猪圈.也就是当客人打开猪圈(他能打开的都打开了)以后,他选择了需要买的猪以后,Mirko可以随意把剩下的猪分配到打开的猪圈中.当然,我

POJ 3281 Dining(最大流建图 &amp;&amp; ISAP &amp;&amp; 拆点)

题目链接:http://poj.org/problem?id=3281 努力练建图ing!!! 题意:有 N 头牛,有 F 种食物和 D 种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料. 第2行-第N+1行.是牛i 喜欢A种食物,B种饮料,及食物种类列表和饮料种类列表. 问最多能使几头牛同时享用到自己喜欢的食物和饮料.->最大流. 本题难点是建图: 思路:一般都是左边一个集合表示源点与供应相连,右边一个集合表示需求与汇点相连. 但是本题,牛作为需求仍然是一个群体,但是供

HDU3338Kakuro Extension(最大流,ISAP)建图是关键

Kakuro Extension Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1144    Accepted Submission(s): 404 Special Judge Problem Description If you solved problem like this, forget it.Because you nee

poj3680 Intervals 区间k覆盖问题 最小费用最大流 建图巧妙

/** 题目:poj3680 Intervals 区间k覆盖问题 最小费用最大流 建图巧妙 链接:http://poj.org/problem?id=3680 题意:给定n个区间,每个区间(ai,bi),以及权值wi.选出一些区间,满足权值和最大且任何一个点不会被超过k个区间覆盖. 思路: 建图:对于每个区间(ai,bi). ai->bi,cap = 1,cost = -wi; (离散化后的ai,bi) 所有区间的端点放到数组,进行从小到大排序,去重,离散化,在数组内相邻的u端点,v端点.u->

poj 3281 最大流+建图

很巧妙的思想 转自:http://www.cnblogs.com/kuangbin/archive/2012/08/21/2649850.html 本题能够想到用最大流做,那真的是太绝了.建模的方法很妙! 题意就是有N头牛,F个食物,D个饮料. N头牛每头牛有一定的喜好,只喜欢几个食物和饮料. 每个食物和饮料只能给一头牛.一头牛只能得到一个食物和饮料. 而且一头牛必须同时获得一个食物和一个饮料才能满足.问至多有多少头牛可以获得满足. 最初相当的是二分匹配.但是明显不行,因为要分配两个东西,两个东