poj 1275 差分约束

来源:互联网 发布:java return递归 编辑:程序博客网 时间:2024/05/01 19:58

Cashier Employment
Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 7150 Accepted: 2662

Description

A supermarket in Tehran is open 24 hours a day every day and needs a number of cashiers to fit its need. The supermarket manager has hired you to help him, solve his problem. The problem is that the supermarket needs different number of cashiers at different times of each day (for example, a few cashiers after midnight, and many in the afternoon) to provide good service to its customers, and he wants to hire the least number of cashiers for this job. 

The manager has provided you with the least number of cashiers needed for every one-hour slot of the day. This data is given as R(0), R(1), ..., R(23): R(0) represents the least number of cashiers needed from midnight to 1:00 A.M., R(1) shows this number for duration of 1:00 A.M. to 2:00 A.M., and so on. Note that these numbers are the same every day. There are N qualified applicants for this job. Each applicant i works non-stop once each 24 hours in a shift of exactly 8 hours starting from a specified hour, say ti (0 <= ti <= 23), exactly from the start of the hour mentioned. That is, if the ith applicant is hired, he/she will work starting from ti o'clock sharp for 8 hours. Cashiers do not replace one another and work exactly as scheduled, and there are enough cash registers and counters for those who are hired. 

You are to write a program to read the R(i) 's for i=0..23 and ti 's for i=1..N that are all, non-negative integer numbers and compute the least number of cashiers needed to be employed to meet the mentioned constraints. Note that there can be more cashiers than the least number needed for a specific slot. 

Input

The first line of input is the number of test cases for this problem (at most 20). Each test case starts with 24 integer numbers representing the R(0), R(1), ..., R(23) in one line (R(i) can be at most 1000). Then there is N, number of applicants in another line (0 <= N <= 1000), after which come N lines each containing one ti (0 <= ti <= 23). There are no blank lines between test cases.

Output

For each test case, the output should be written in one line, which is the least number of cashiers needed. 
If there is no solution for the test case, you should write No Solution for that case. 

Sample Input

11 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1502322110

Sample Output

1

Source

Tehran 2000

题目要找最少可能的雇佣人数。首先,最基本的条件是每个时间点要满足工作的人数>=r[i],也就是在i的前八个小时内雇佣的人数之和>=r[i],

因此可以定义一个S[i],到时间点i为止雇佣的总人数。区间[a,b]雇佣的人数就为Sb-S(a-1), 为了方便,补一个0点,其它点在原来位置上加1, 1.....24.然后逐步确定条件:

1.八个小时内雇佣人数>=r[i],  S[i]-S[i-8] >= r[i] (i>= 8) ,   

    tot-(S[i-8+24]-S[i]) >= r[i], (i<8)  // tot 为雇佣的总人数

2.S[i]>=S[i-1]

3.雇佣人数不能超过应聘人数, S[i]-S[i-1] <= t[i],  t[i]为i时刻应聘的人数

4. S[24]-S[0] <= tot

这里tot是不确定的,但是一旦确定总人数tot,就可以建立图论模型,应聘的总人数就等于d[24]-d[0]求最长路

因此可以枚举或者二分tot人数,求最长路判断是否符合条件


#include <iostream>#include <cstring>#include <cstdio>#include <queue>using namespace std;#define maxn 1005#define inf 0x3f3f3f3fstruct edge{    int v,w,next;    edge() {}    edge(int v_, int w_, int next_){ v=v_; w=w_; next=next_;}};edge g[maxn]; int top;int first[25];void add(int u, int v, int w){    g[top] = edge(v, w, first[u]);    first[u] = top++;}int n;int t[25], r[25];void build(int tot) //建图{    memset(first, -1, sizeof(first));    top = 0;    for(int i = 1; i <= 24; i++)        add(i-1, i,0);    for(int i = 1; i <= 24; i++)        add(i,i-1,-t[i]);    for(int i = 8; i <= 24; i++)        add(i-8, i, r[i]);    for(int i = 1; i < 8; i++)        add(i+16, i, -tot+r[i]);    add(0, 24, tot);}int in[25];int dist[25];int cnt[25];int spfa(){    memset(in, 0, sizeof(in));    memset(dist, -inf, sizeof(dist));    memset(cnt, 0, sizeof(cnt));    queue<int> que;    que.push(0);    dist[0] = 0;    cnt[0]++;    while(!que.empty()){        int u = que.front(); que.pop();        in[u] = 0;        for(int i = first[u]; i != -1; i = g[i].next){            int v = g[i].v, w = g[i].w;            if(dist[u]+w>dist[v]){      //最长路                dist[v] = dist[u]+w;                if(!in[v]){                    que.push(v);                    in[v]=1;                    cnt[v]++;                    if(cnt[v]>24) return 0; //判断正环,若存在正环则不存在最长路                }            }        }    }    return 1;}int main(){    int test;    scanf("%d", &test);    while(test--){        for(int i = 1; i <= 24; i++)            scanf("%d", r+i);        memset(t, 0, sizeof(t));        int n, tmp;        scanf("%d", &n);        for(int i = 0; i < n; i++){            scanf("%d", &tmp);            t[tmp+1]++;        }        int ans=-1;        int l = 0, r = n+1, m;        while(l<r){     //  二分总人数            m = l+(r-l)/2;            build(m);            if(!spfa())                l = m+1;            else{                ans = m;                r = m;            }        }       if(ans!=-1)        printf("%d\n", ans);        else            printf("No Solution\n");    }    return 0;}




0 0