poj1275 Cashier Employment

题目大意:
            德黑兰的一家每天24小时营业的超市,需要一批出纳员来满足它的需求。超市经理雇佣你来帮他解决一个问题————超市在每天的不同时段需要不同数目的出纳员(例如,午夜只需一小批,而下午则需要很多)来为顾客提供优质服务,他希望雇佣最少数目的纳员。
            超市经历已经提供一天里每一小时需要出纳员的最少数量————R(0),R(1),...,R(23)。R(0)表示从午夜到凌晨1:00所需要出纳员的最少数目;R(1)表示凌晨1:00到2:00之间需要的;等等。每一天,这些数据都是相同的。有N人申请这项工作,每个申请者i在每天24小时当中,从一个特定的时刻开始连续工作恰好8小时。定义ti(0<=ti<=23)为上面提到的开始时刻,也就是说,如果第i个申请者被录用,他(或她)将从ti时刻开始连续工作8小时。
            试着编写一个程序,输入R(i),i=0,...,23,以及ti,i=1,...,N,它们都是非负整数,计算为满足上述限制需要雇佣的最少出纳员数目、在每一时刻可以有比对应R(i)更多的出纳员在工作
输入描述:
            输入文件的第1行为一个整数T,表示输入文件中测试数据的数目(至多20个)。每个测试数据第一行为24个整数,表示R(0),R(1),...,R(23),R(i)最大可以取到1000。接下来一行是一个整数N,表示申请者的数目,0<=N<=1000。接下来有N行,每行为一个整数ti,0<=ti<=23,测试数据之间没有空行。
输出描述:
           对输入文件中的每个测试数据,输出占一行,为需要雇佣的出纳员的最少数目。如果某个测试数据没有解。则输出"No Solution"。

分析:这道题很难啊,变态夏令营老师竟然把这当作业,做完之后感觉对差分约束系统又有更深一步的了解。

      差分约束系统的关键就是要找不等式,然后化成一种形式,跑最长路/最短路,关键就是这个不等式要怎么找,黑书上有详细的解释:

 

其实也用不到二分法,直接枚举就好了,我们spfa求出来的d[24]其实是s[24] - s[0],因为我们人为规定s[0] = 0,所以d[24]也就是答案了。

到目前为止遇到了两类差分约束系统的问题,一类是告诉你sum,问你有没有解,第二种是告诉你条件,求解,第二种枚举解就好了,第一种就是判环.

坑的是我最长路写错了,有存在边权为0的情况,所以d数组每次都要初始化为-1.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<map>

using namespace std;

const int inf = 0x7ffffff;

int T,t[30],r[30],ans,n,head[110],to[110],nextt[110],w[110],tot,d[110],vis[110],cnt[110];

void add(int x, int y, int z)
{
    w[tot] = z;
    to[tot] = y;
    nextt[tot] = head[x];
    head[x] = tot++;
}

void build(int sum)
{
    memset(head, -1, sizeof(head));
    tot = 0;
    add(0, 24, sum);
    for (int i = 1; i <= 24; i++)
    {
        add(i - 1, i, 0);
        add(i, i - 1, -t[i]);
    }
    for (int i = 1; i <= 8; ++i)
        add(i + 16, i, r[i] - sum);
    for (int i = 9; i <= 24; ++i)
        add(i - 8, i, r[i]);
}

bool spfa(int sum)
{
    memset(vis, 0, sizeof(vis));
    memset(cnt, 0, sizeof(cnt));
    memset(d, -1, sizeof(d));
    queue <int>q;
    vis[0] = 1;
    q.push(0);
    d[0] = 0;
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for (int i = head[u]; i + 1; i = nextt[i])
        {
            int v = to[i];
            if (d[v] < d[u] + w[i])
            {
                d[v] = d[u] + w[i];
                if (!vis[v])
                {
                    ++cnt[v];
                    if (cnt[v] > 24)
                    return false;
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }
    if (d[24] == sum)
        return true;
    return false;
}

int main()
{
    scanf("%d", &T);
    while (T--)
    {
        bool flag = false;
        memset(t, 0, sizeof(t));
        for (int i = 1; i <= 24; i++)
            scanf("%d", &r[i]);
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
        {
            int x;
            scanf("%d", &x);
            t[x + 1]++;
        }
        for (int i = 0; i <= n; ++i)
        {
            build(i);
            if (spfa(i))
            {
                flag = true;
                printf("%d\n", i);
                break;
            }
        }
        if (!flag)
        {
            printf("No Solution\n");
        }
    }

    return 0;
}

 

posted @ 2017-08-20 23:14  zbtrs  阅读(292)  评论(0编辑  收藏  举报