POJ-1275 Cashier Employment

题目链接:

https://vjudge.net/problem/POJ-1275

题意:

对于0到23、总共24个时刻,每个时刻至少需要r[i]个人,现在有m个人应聘,每个人开始的工作时间为t[i],且每个人都要工作八小时,求需要的最少人数。

分析:

为了方便,不妨对每个时刻加一,将0到23变为1到24。设s[i]为从0时刻到i时刻的总人数,num[i]为从i时刻开始工作的人数,那么根据题意可以得到以下不等式:

(由于求最小值,这里所有不等式写成A-B>=c的形式)

(1)s[i]-s[i-1]>=0(s单调递增)

(2)s[i-1]-s[i]>=-num[i](i时刻新增的人数不大于从i时刻开始工作的人数)

(3)如果i>=8,那么有s[i]-s[i-8]>=r[i](从i-7到i时刻的总人数要不小于r[i])

(4)如果i<8,那么有s[i]-s[i+16]>=r[i]-s[24](通过变形容易知道)

(5)s[24]-s[0]>=s[24]

(6)s[0]-s[24]>=-s[24](s[24]是一个待枚举的定值,且s[0]=0,将s[24]-s[0]=s[24]变为两条不等式)

以0为超级源点,由前两条不等式保证从0能到达所有顶点。从1到m升序枚举s[24],根据以上不等式建图,判断是否有负环。如果没有负环说明存在一组可行解,输出当前枚举到的值。如果枚举完都不存在解,输出No Solution。

代码(这里用的是bellman-ford判断负环。spfa?它死了):

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <vector>
 5 #include <queue>
 6 #include <map>
 7 #include <set>
 8 #include <cstring>
 9 const int INF=0x3f3f3f3f;
10 using namespace std;
11 struct edge
12 {
13     int u,v,w;
14 }e[10000];
15 int t,m,cnt,r[25],num[25],dis[25];
16 void add(int u,int v,int w)
17 {
18     ++cnt;
19     e[cnt].u=u;
20     e[cnt].v=v;
21     e[cnt].w=w;
22 }
23 bool bellman_ford(int k)
24 {
25     memset(dis,-INF,sizeof(dis));
26     cnt=0;
27     dis[0]=0;
28     for(int i=1;i<=24;++i)
29     {
30         add(i-1,i,0);
31         add(i,i-1,-num[i]);
32         if(i>=8)add(i-8,i,r[i]);
33         else add(i+16,i,r[i]-k);
34     }
35     add(0,24,k);
36     add(24,0,-k);
37     int i,j;
38     for(i=1;i<=25;++i)
39     {
40         int flag=0;
41         for(j=1;j<=cnt;++j)
42         {
43             if(dis[e[j].v]<dis[e[j].u]+e[j].w)
44             {
45                 dis[e[j].v]=dis[e[j].u]+e[j].w;
46                 flag=1;
47             }
48         }
49         if(!flag)break;
50     }
51     return i<26;
52 }
53 void solve()
54 {
55     for(int i=1;i<=m;++i)
56     {
57         if(bellman_ford(i))
58         {
59             printf("%d\n",i);
60             return;
61         }
62     }
63     printf("No Solution\n");
64     return;
65 }
66 int main(void)
67 {
68     scanf("%d",&t);
69     while(t--)
70     {
71         for(int i=1;i<=24;++i)scanf("%d",&r[i]);
72         scanf("%d",&m);
73         memset(num,0,sizeof(num));
74         for(int i=1;i<=m;++i)
75         {
76             int x;
77             scanf("%d",&x);
78             ++num[x+1];
79         }
80         solve();
81     }
82     return 0;
83 }

 

时间复杂度:O(tm),其中m为应聘的人数。实际上最坏情况下需要跑m遍bellman-ford,而bellman-ford的时间复杂度为O(VE),V为图的顶点数,E为图的边数。但在本题中V=25,E=O(V),O(VE)为常数级,从而使整体的复杂度由O(tmVE)变为O(tm)。

空间复杂度:O(1),所有存储空间都有不随任何变量变化的常数上界。

 

posted @ 2021-06-18 21:36  yanying  阅读(91)  评论(0编辑  收藏  举报