POJ 1275/HDU 1529 Cashier Employment (差分约束)

POJ链接
HDU链接

题意:一个商店,告诉你一天每个小时里至少需要的人数,以及来应聘的人数的工作的起始时间,固定工作8小时,求最少应该雇佣的人数。

思路:设 s[i] 表示在前 i 小时,总开始工作的人数,所以, i>=8时, 有 s[i] - s[i-8] >= i时刻需要的人数,
i<8 时, 有 s[i]+s[24]-s[i+16]>=i时刻需要的人数 。 同时,对于相邻时间会有 0<=s[i] - s[i-1]<=i时刻开始工作的人数。在这里会发现 s[24] 就是我们要求的答案,但就这样的话还是求不出,所以枚举s[24];

想法:难点在建立不等式,即建图。(大佬厉害)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
const int maxn = 50;
const int inf = 0x3f3f3f3f;
using namespace std;
struct note{
    int to, w;
    note(int to1, int w1){
        to = to1, w = w1;
    }
};
vector <note> maps[maxn];
int need[maxn], work[maxn], ans;
//need[i] i时刻需要的人数
//work[i] i时刻开始工作的人数


void init(){//要枚举答案, 所以每次要初始化,并建图
    for(int i=0; i<=24; i++)
        maps[i].clear();
    for(int i=1; i<=24; i++){
        maps[i-1].push_back(note(i, 0));	// s[i] - s[i-1] >= 0
        maps[i].push_back(note(i-1, -work[i]));
        //s[i] - s[i-1] <= work[i]  --->  s[i-1] - s[i] >= -work[i]
        if(i>=8)
            maps[i-8].push_back(note(i, need[i]));	//s[i] - s[i-8] >= need[i]
        else
            maps[16+i].push_back(note(i, need[i]-ans)); //s[i] - s[i+16] >= need[i]-ans
    }
    maps[0].push_back(note(24, ans));	//s[24]-s[0]>=ans  (容易忘记)
}

bool spfa(){
    int dis[maxn], cnt[maxn];
    //图有可能回出现负环, cnt[i] 记录 i 点入队列的次数
    bool vis[maxn];
    for(int i=0; i<=24; i++)
        dis[i] = -inf, vis[i] = false, cnt[i] = 1;
    dis[0] = 0, vis[0] = true, cnt[0] = 1;
    queue <int> q;
    q.push(0);
    while(!q.empty()){
        int u = q.front();
        q.pop();
        vis[u] = false;
        for(int i=0, len = maps[u].size(); i<len; i++){
            int v = maps[u][i].to, w = maps[u][i].w;
            if(dis[v] < dis[u] + w){
                dis[v] = dis[u] + w;
                if(!vis[v]){
                    cnt[v]++;
                    if(cnt[v] > 24)
                        return false; //存在负环,无解
                    vis[v] = true;
                    q.push(v);
                }
            }
        }
    }
    if(dis[24] == ans)
        return true;
    return false;
}

int main()
{
    int t;
    scanf("%d", &t);
    while(t--){
        for(int i=1; i<=24; i++){
            scanf("%d", &need[i]);
        }
        int n;
        scanf("%d", &n);
        for(int i=1; i<=n; i++){
            int j;
            scanf("%d", &j);
            work[j+1]++;
        }
        for(ans=0; ans<=n; ans++){ //枚举
            init();
            if(spfa()){
                break;
            }
        }
        if(ans > n)
            printf("No Solution
");
        else
            printf("%d
", ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/jizhihong/p/13337363.html