POJ 1275 Vijos 1108 小胖超市

小胖超市

描述:

xuzhenyi的一家每天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)更多的出纳员在工作。

格式:

输入格式:

输入文件的第一行为测试点个数(<= 20)。每组测试数据的第一行为24个整数表示R(0),R(1),…, R(23)(R(I)<= 1000)。接下来一行是N,表示申请者数目(0 <= N <= 1000),接下来每行包含一个整数tI (0 <= tI <= 23)。两组测试数据之间没有空行。

输出格式:

对于每个测试点,输出只有一行,包含一个整数,表示需要出纳员的最少数目。如果无解,你应当输出“No Solution”。

样例1

样例输入1

1
1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
5
0
23
22
1
10

样例输出1

1

来源

huyichen

/*
约分差束--最小值--最长路
注意判断负环回路
算法分析:
设num[i] 为来应聘的在第i个小时开始工作的人数
r[i] 为第i个小时至少需要的人数
x[i] 为招到的在第i个小时开始工作的人数
根据题意有:
0 <= x[i] <= num[i]
x[i] + x[i-1] + …+ x[i-7] >= r[i] (题目中的连续工作8小时)
再设 s[i] = x[1] + … + x[i]
则有: s[i] – s[i-1] >= 0
s[i-1] – s[i] >= –num[i]
s[i] – s[i-8] >= r[i], 8 <= i <= 24
s[i] – s[i+16] >= r[i] – s[24],  1<= i <= 7
还需要添加一个隐藏不等式: s[24] – s[0] >= ans(枚举的答案)
通过枚举s[24],来检测是否满足条件,题目是求最小值,即求最长路,以0为源点。
*/
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<cstdlib>
using namespace std;
#define maxn 1200
#define INF 0x7fffffff
struct Edge{ int to,w,next; }e[maxn];
int head[maxn],dis[maxn],tot;
int r[maxn],num[maxn],n,cnt[maxn];
bool exist[maxn];
void Add_Edge(int u,int v,int w){
    e[tot].to=v;e[tot].w=w;
    e[tot].next=head[u];head[u]=tot++;
}
void Built(int ans){
    tot=0;
    memset(head,-1,sizeof head );
    Add_Edge(0,24,ans);
    for(int i=1;i<=24;i++){
        Add_Edge(i-1,i,0);
        Add_Edge(i,i-1,-num[i]);
    }
    for(int i=1;i<=8;i++)
        Add_Edge(i+16,i,r[i]-ans);
    for(int i=9;i<=24;i++)
        Add_Edge(i-8,i,r[i]);
    return ;
}
queue<int> q;
bool SPFA(int ans){
    while(!q.empty()) q.pop();
    for(int i=1;i<=24;i++){
        dis[i]=-INF;
        cnt[i]=0;
        exist[i]=false;
    }
    q.push(0);exist[0]=true;dis[0]=0;
    while(!q.empty()){
        int u=q.front();q.pop();exist[u]=false;
        for(int i=head[u];i!=-1;i=e[i].next){
            int v=e[i].to,w=e[i].w;
            if(dis[v]<dis[u]+w){
                dis[v]=dis[u]+w;
                if(!exist[v]){
                    exist[v]=true;
                    q.push(v);
                }
                cnt[v]++;
                if(cnt[v]>24) return 0;
            }
        }
    }
    if(dis[24]==ans) return 1;
    else return 0;
}
int main(){
    int Test;cin>>Test;
    while(Test--){
        bool flag=false;
        for(int i=1;i<=24;i++){
            scanf("%d",&r[i]);//r[i]表示第i时刻需要
            //多少人提供服务,但是要注意r[i]实际表示i-1
            //时刻的数据
            num[i]=0;
        }
        scanf("%d",&n);
        for(int t,i=1;i<=n;i++){
            scanf("%d",&t);
            num[t+1]++;
        }
        for(int i=1;i<=n;i++){
            Built(i);
            if(SPFA(i)==1){
                flag=true;
                printf("%d\n",i);
                break;
            }
        }
        if(flag==false){
            printf("No Solution\n");
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七情六欲·

学生党不容易~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值