zoukankan      html  css  js  c++  java
  • 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
    ",i);
    60             return;
    61         }
    62     }
    63     printf("No Solution
    ");
    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),所有存储空间都有不随任何变量变化的常数上界。

    终究独木难支。
  • 相关阅读:
    《Python 源码阅读》之 类型Type
    《Python 源码剖析》之对象
    KMP匹配算法
    Python的递归深度
    js验证手机号
    Jquery 实现 “下次自动登录” 记住用户名密码功能
    js注册读秒进度条
    div+css进度条
    SprignMVC+myBatis整合
    ssm控制输出sql(二)
  • 原文地址:https://www.cnblogs.com/yanying7/p/14901283.html
Copyright © 2011-2022 走看看