标签:kebab hdu 2883 网络流判满流 关键是缩点
2 10 1 10 6 3 2 10 4 2 2 10 1 10 5 3 2 10 4 2
Yes No
题意:有一个烧烤机,每次最多能烤 m 块肉,现在有 n 个人来买烤肉,每个人到达时间为 si,离开时间为 ei,点的烤肉数量为 ci,每个烤肉所需烘烤时间为 di,注意一个烤肉可以切成几份来烤。
思路:这一题和hdu 3572 Task Schedule有一点点像,但这一题时间的范围跨度太大,不能再每个时刻看成一个点了,要进行缩点,这一点很巧妙,我没想到。将所有的到达时间和结束时间按升序排序,得到 x <= 2n-1 个时间区间。建立网络流模型:s为源,t为汇,每个顾客i作为一个结点并连边(s, i, ni*ti),每个区间j作为一个结点并连边(j, t, (ej-sj)*M),其中sj, ej分别表示区间j的起始时间和终止时间。对任意顾客i和区间j,若 [sj, ej] 完全包含在 [si, ei] 之中,则连边(i, j, INF)。若最大流等于 ∑ni*ti 则是 Yes,否则是 No。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define maxn 1005
#define MAXN 2005
#define mod 1000000009
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define FRE(i,a,b)  for(i = a; i <= b; i++)
#define FREE(i,a,b) for(i = a; i >= b; i--)
#define FRL(i,a,b)  for(i = a; i < b; i++)
#define FRLL(i,a,b) for(i = a; i > b; i--)
#define mem(t, v)   memset ((t) , v, sizeof(t))
#define sf(n)       scanf("%d", &n)
#define sff(a,b)    scanf("%d %d", &a, &b)
#define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)
#define pf          printf
#define DBG         pf("Hi\n")
typedef long long ll;
using namespace std;
struct Edge
{
    int u,v,cap,next;
}edge[MAXN];
int n,m,num,sum,cnt;
int level[maxn],head[maxn],cur[maxn];
int S[maxn],E[maxn],N[maxn],T[maxn],a[maxn];
void init()
{
    num=0;cnt=0;sum=0;
    mem(head,-1);
}
void addedge(int u,int v,int w)
{
    edge[num].u=u; edge[num].v=v; edge[num].cap=w; edge[num].next=head[u]; head[u]=num++;
    edge[num].u=v; edge[num].v=u; edge[num].cap=0; edge[num].next=head[v]; head[v]=num++;
}
bool bfs(int s,int t)
{
    mem(level,-1);
    level[s]=0;
    queue<int>Q;
    Q.push(s);
    while (!Q.empty())
    {
        int u=Q.front(); Q.pop();
        for (int i=head[u];i+1;i=edge[i].next)
        {
            int v=edge[i].v;
            if (level[v]==-1&&edge[i].cap>0)
            {
                level[v]=level[u]+1;
                Q.push(v);
            }
        }
    }
    return level[t]!=-1;
}
int dfs(int u,int t,int f)
{
    if (u==t) return f;
    for (int &i=cur[u];i+1;i=edge[i].next)
    {
        int v=edge[i].v;
        if (level[v]==level[u]+1&&edge[i].cap>0)
        {
            int d=dfs(v,t,min(f,edge[i].cap));
            if (d>0)
            {
                edge[i].cap-=d;
                edge[i^1].cap+=d;
                return d;
            }
        }
    }
    return 0;
}
int dinic(int s,int t,int nodenum)
{
    int flow=0,f;
    while (bfs(s,t))
    {
        for (int i=0;i<=nodenum;i++) cur[i]=head[i];
        while ((f=dfs(s,t,INF))>0)
            flow+=f;
    }
    return flow;
}
int main()
{
    int i,j;
    while (~scanf("%d%d",&n,&m))
    {
        init();
        for (i=1;i<=n;i++)
        {
            scanf("%d%d%d%d",&S[i],&N[i],&E[i],&T[i]);
            a[cnt++]=S[i];
            a[cnt++]=E[i];
            sum+=N[i]*T[i];
            addedge(0,i,N[i]*T[i]);
        }
        sort(a,a+cnt);
        cnt=unique(a,a+cnt)-a;
        for (i=0;i<cnt-1;i++)
        {
            addedge(n+i+1,n+cnt,(a[i+1]-a[i])*m);
            for (j=1;j<=n;j++)
                if (a[i]>=S[j]&&a[i+1]<=E[j])
                    addedge(j,n+i+1,INF);
        }
        int ans=dinic(0,n+cnt,n+cnt+1);
//        printf("%d\n",ans);
        if (ans==sum) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}
标签:kebab hdu 2883 网络流判满流 关键是缩点
原文地址:http://blog.csdn.net/u014422052/article/details/45157469