HDU2883kebab(离散化+最大流_任务分配)

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2883

题意:

       给定n个顾客,第i号顾客在si到达,点了ni个羊肉串,每个羊肉串需要ti个时间烤好。顾客想要在ei得到,一个烤炉只烤m串。问你是否能满足所有顾客的要求?能的话输出“Yes”,否则输出“No”。

注意:这ni个羊肉串可以被分开来考,一个单独的羊肉串也能分开烤(比如一个单独的羊肉串需要ti时间,我们把它分成ti份同时烤的话,那么一个羊肉串可以在1个单位时间内拷完)

注意:每个顾客的任务必须在(si,ei]半开半闭的区间内完成.


基本的任务分配题,还是附上大神的讲解:http://blog.csdn.net/u013480600/article/details/38984057


分析:

       本题与HDU3572有点类似:

http://blog.csdn.net/rain722/article/details/54601227

其实本题的本质就是HDU3572的思想,每个顾客其实提出的是需要ni*ti个单位时间任务(甚至可以在1个时刻同时完成,因为一串羊肉串都可以在1个时刻烤完),但是你每个时间只能提供m个单位时间做任务. 但是这个题目的时间点覆盖1到100W,明显不能再把每个单独的时间看成一个点了,所以这题要把每个不重叠的子时间区间看成一个点.

       首先读入所有任务的开始时间s[i]和结束时间e[i],然后对这些时间点排序,去重,得到cnt个时间点,然后我们就能得到cnt-1个半开半闭的子时间区间(前后两个子区间边界不重叠,且所有区间连起来正好覆盖了原来的整个大时间区间,该大时间区间也是半开,半闭的).

       建图: 源点s编号0,  n个任务编号1到n,  cnt-1个区间编号n+1到n+cnt,  汇点t编号n+cnt+1.

       源点到每个任务i有边(s,i,ni*ti)

       每个时间区间j到汇点有边(j,t, 该区间覆盖的单位时间点数)

       如果任务i包含时间区间j,那么有边(i,j,INF)

       求最大流,看最大流 是否== 所有任务需要的单位时间之和即可.

 AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define PI acos(-1.0)
#define eps 1e-8
#define ll long long
#define MEM(a, b) memset(a, b, sizeof(a))
#define pb push_back
#define mp make_pair
#define MII map<int,int>::iterator
#define MLL map<LL,LL>::iterator
#define pii pair<int,int>
#define SI set<int>::iterator
#define SL set<LL>::iterator
#define dug printf("bug-------bug-------bug\n")
using namespace std;
const int maxn = 600+5;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int from, to, cap, flow;
    Edge(){}
    Edge(int f, int t, int c, int fl):from(f), to(t), cap(c), flow(fl){}
};
struct Dinic
{
    int n, m, s, t;
    vector<Edge> edges;
    vector<int> G[maxn];
    int d[maxn];
    int cur[maxn];
    bool vis[maxn];
    void init(int n, int s, int t)
    {
        this->n = n;this->s = s;this->t = t;
        edges.clear();
        for(int i = 0; i < n; i++)
            G[i].clear();
    }
    void AddEdge(int from, int to, int cap)
    {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, 0, 0));
        m = edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }
    bool BFS()
    {
        queue<int> q;
        memset(vis, false, sizeof(vis));
        vis[s] = true;
        d[s] = 0;
        q.push(s);
        while(!q.empty())
        {
            int x = q.front();
            q.pop();
            for(int i = 0; i < G[x].size(); i++)
            {
                Edge e = edges[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 = edges[G[x][i]];
            if(d[e.to] == d[x]+1 && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0)
            {
                e.flow += f;
                edges[G[x][i]^1].flow -= f;
                flow += f;
                a -= f;
                if(a == 0)
                    break;
            }
        }
        return flow;
    }
    int max_flow()
    {
        int ans = 0;
        while(BFS())
        {
            memset(cur,0,sizeof(cur));
            ans += DFS(s, INF);
        }
        return ans;
    }
}DC;
int N, M;
int s[maxn], n[maxn], e[maxn], t[maxn];
int time[maxn];
int full_flow;
int main()
{
    while(scanf("%d%d", &N, &M) == 2)
    {
        full_flow = 0;
        int cnt = 0;
        for(int i = 1; i <= N; i++)
        {
            scanf("%d%d%d%d", &s[i], &n[i], &e[i], &t[i]);
            time[cnt++] = s[i];
            time[cnt++]= e[i];
            full_flow += n[i]*t[i];
        }
        sort(time, time+cnt);
        cnt = unique(time, time+cnt) - time;
        int src = 0, dst = N + cnt + 1;
        DC.init(N+cnt+2, src, dst);

        for(int i = 1; i <= N; i++)
            DC.AddEdge(src, i, n[i]*t[i]);
        for(int i = 1; i <= cnt-1; i++)
        {
            DC.AddEdge(N+i, dst, (time[i]-time[i-1])*M);
            for(int j = 1; j <= N; j++)
                if(s[j] <= time[i-1] && time[i] <= e[j])
                    DC.AddEdge(j, N+i, INF);
        }
        printf("%s\n", DC.max_flow() == full_flow ? "Yes":"No");
    }
    return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值