poj——1275 Cashier Employment 差分约束系统

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情
Cashier Employment

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

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

Sample Output

1

分析:
约束条件分析,为方便分析,我们把讨论区间由[0,23]改为[1,24]
设apply[i] 为来应聘的在第i个小时开始工作的总人数
设R[i] 为第i个小时至少需要的人数
设X[i] 为实际雇佣的在第i个小时开始工作的总人数
设S[i] = X[1] + … + X[i]   (第1到第i个小时一共雇佣的总人数)
约束条件:
由于0<=x[i]<=apply[i],于是
1> s[i]-s[i-1]>=0;
2> s[i]-s[i-1]<=apply[i] <=> s[i-1]-s[i]>=-apply[i];
由于题目限制:
3> s[i]-s[i-8]>=R[i](8<=i<=24)
4> s[i]-s[i+16]>=R[i]-s[24]  (i<8)  (*)
(*)不等式中,s[24](也是最后要求的)为变量,于是需要二分答案;
二分答案为p后,注意假设了s[24]==p;
于是 5> s[24]-s[0]>=p  && s[0]-s[24]<= -p;
注意,这一条必须加入图中一起跑,不能最后单独判定,因为s[24]不是一个独立的变量,与其他变量有关。
最后,求最小,跑最长路即可。
代码如下:
<pre name="code" class="cpp">#include<cstdio>      
#include<iostream>    
#include<cstring>      
#include<queue>      
#include<vector>       
    
#define LL long long      
#define CLEAR(XXX) memset((XXX),0,sizeof(XXX))   
   
using namespace std;        
const int inf=1e9;      
const int maxn=1000+5,maxm=100005;      
  
int n,apply[30],R[30];      
inline void _read(int &x){      
    char ch=getchar(); bool mark=false;      
    for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true;      
    for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';      
    if(mark)x=-x;      
}      
struct Edge{      
    int from,to,w;      
    Edge(int from,int to,int w):from(from),to(to),w(w){}    
};   
  
vector<Edge> edge;      
int last[maxm],Next[maxm];      
int dist[maxn];      
int cnt[maxn];      
bool vis[maxn];   
      
struct SPFA{      
    int  n,m;          
    void init(int n){      
        this->n = n; m=0;      
        CLEAR(last);  CLEAR(Next);      
        edge.clear();      
        edge.push_back(Edge(0,0,0));      
    }      
    void add_edge(int from,int to,int dist){      
        edge.push_back(Edge(from,to,dist));      
        m=edge.size()-1;      
        Next[m]=last[from];      
        last[from]=m;      
    }      
    bool solve(int s){      
        int i;      
        CLEAR(vis); CLEAR(cnt);        
        for(i=1;i<=n;i++) dist[i]= -inf;      
        dist[s]=0;    
        vis[s]=true;cnt[s]++;      
        queue <int> q;   
        q.push(s);      
        while(!q.empty()){      
            int x=q.front();      
            q.pop();vis[x]=false;     
            for(i=last[x];i;i=Next[i]){      
                Edge& e=edge[i];      
                if(dist[e.from]+e.w>dist[e.to]){   //最少,用最长路   
                    dist[e.to]=dist[e.from]+e.w;      
                    if(!vis[e.to]){      
                        cnt[e.to]++;      
                        if(cnt[e.to]==n+1)return false;      
                        q.push(e.to) ;      
                        vis[e.to]=true;      
                    }      
                }       
            }      
        }      
        return true;      
    }      
    void answer(){      
        for(int i=1;i<=n;i++)      
            if(dist[i]>=inf)printf("NoPath\n");      
            else printf("%d\n",dist[i]);      
    }      
};  
SPFA solver;  
bool check(int p){  //二分ans,就是s[24];  
    int i;   
    solver.init(24);  
    for(i=1;i<=24;i++){  
        solver.add_edge(i-1,i,0); //1> s[i]-s[i-1]>=0;  
        solver.add_edge(i,i-1,-apply[i]);  
         //2> s[i]-s[i-1]<=apply[i] <=> s[i-1]-s[i]>=-apply[i];  
        solver.add_edge(0,i,0);  
        if(i>=8)solver.add_edge(i-8,i,R[i]); //3> s[i]-s[i-8]>=r[i];  (8<=i<=24)  
        else solver.add_edge(i+16,i,R[i]-p);  
        //4> s[i]-s[i+16]>=r[i]+p  
    }  
    solver.add_edge(0,24,p);  // 5> dist[24]-dist[0]==p; 
	solver.add_edge(24,0,-p); 
    return solver.solve(0);

}       
int main(){     
     //freopen("ans.out","w",stdout);   
     int t,i,x,j,l,r,y;  
     _read(t);  
     while(t--){  
        CLEAR(R); CLEAR(apply);  
        for(i=1;i<=24;i++)_read(R[i]);  
        _read(n);    
        for(i=1;i<=n;i++){  
            _read(x);  apply[x+1]++;  
        }  
        l=0;r=n;  
        while(l<=r){  
            int mid=(l+r)>>1;  
            check(mid)? (r=mid-1):(l=mid+1);  
         }  
         if(check(l)&&l<=n)printf("%d\n",l);  
         else puts("No Solution");  
     }  
     return 0;  
}     


another version

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
const int inf=-1e9;
using namespace std;
int dis[5005],next[100005],last[100005];
bool vis[5005];
int cnt[5005];
int num[25];
int r[25];
int m=0;
int n=24;
struct edge{
	int from,to,len;
	edge(){}
	edge(int a,int b,int c){from=a;to=b;len=c;}
};
edge line[100005];
inline void read(int &x){  
    char t;  
    bool mark=false;  
    for(;t=getchar(),t<'0'||t>'9';) if(t=='-') mark=1;  
    for(x=t-'0',t=getchar();'0'<=t&&t<='9';x=x*10+t-'0',t=getchar());  
    x=mark?-x:x;  
}
void add_edge(int from,int to,int len){
	m++;
	next[m]=last[from];
	last[from]=m;
	line[m]=edge(from,to,len);
}
void check_clear(){
	memset(next,0,sizeof(next));
	memset(last,0,sizeof(last));
	memset(dis,0,sizeof(dis));
	memset(line,0,sizeof(line));
}
void init_clear(){
	memset(next,0,sizeof(next));
	memset(last,0,sizeof(last));
	memset(dis,0,sizeof(dis));
	memset(line,0,sizeof(line));
	memset(r,0,sizeof(r));
}
bool spfa(int s){
	queue<int>q;
	memset(vis,0,sizeof(vis));
	memset(cnt,0,sizeof(cnt));
	int i,j,k,t;
	for(i=1;i<=n;i++)dis[i]=inf;
	vis[s]=true;
	dis[s]=0;
	cnt[s]++; 
	q.push(s);
	while(q.size()){
		t=q.front();q.pop();vis[t]=false;
		for(i=last[t];i;i=next[i]){
			if(dis[line[i].to]<dis[line[i].from]+line[i].len){
				dis[line[i].to]=dis[line[i].from]+line[i].len;
				if(vis[line[i].to]==false){
					cnt[line[i].to]++;
					if(cnt[line[i].to]>=n+1){
						return false;
					}
					q.push(line[i].to);
					vis[line[i].to]=true;
				}
			}
		}
	}
	return true;
}
bool check(int mid){
	check_clear();
	bool flag;
	int i,j,k;
	m=0;
	for(i=1;i<=24;i++)add_edge(i-1,i,0);
	for(i=1;i<=24;i++)add_edge(i,i-1,-num[i]);
	for(i=8;i<=24;i++)add_edge(i-8,i,r[i]);
	for(i=1;i<=7;i++)add_edge(i+16,i,r[i]-mid);
	for(i=1;i<=24;i++)add_edge(0,i,0);
	add_edge(0,24,mid);
	add_edge(24,0,-mid);
	flag=spfa(0);
	//if(flag==false)cout<<m id<<" fuck"<<endl;
	//else cout<<mid<<" "<<dis[24]<<" "<<dis[0]<<endl;
	if(flag==false)return false;
	//if(dis[n]>mid)return false;
	else return true;
}
int main(){
	int h;
	cin>>h;
	while(h--){
		//s[i]-s[i-1]>=0
		//s[i-1]+num[i]>=s[i]
		//s[i]-s[i-8]>=num[i]  (8=<i<=24)
		//s[24]-s[i+16]+s[i]>=r[i]   (1<=i<=7)
		init_clear();
		int minn=1,maxn,tot;
		int i,j,k,x;
		m=0;
		for(i=1;i<=24;i++)scanf("%d",&r[i]);
		scanf("%d",&tot);
		for(i=1;i<=tot;i++){
			scanf("%d",&x);
			num[x+1]++;
		}
		maxn=tot;
		while(minn<=maxn){
			int mid=(minn+maxn)/2;
			if(check(mid))maxn=mid-1;
			else minn=mid+1;
		}
		if(check(minn)==false)cout<<"No Solution"<<endl;
		else cout<<minn<<endl;
	}
}



POJ1275 Cashier Employment差分约束系统 + 二分答案) POJ1275 Cashier Employment原题地址:http://poj.org/problem?id=1275题意: 德黑兰的一家每天24小时营业的超市,需要一批出纳员来满足它的需求。超市经理雇佣你来帮他解决一个问题————超市在每天的不同时段需要不同数目的出纳员(例如,午夜只需一小批,而下午则需要很多)来为顾客提供优质服务,他希望雇佣最少数目的纳员。 阅读详情

相关推荐

POJ 1275Cashier Employment差分约束系统的建立和求解)

POJ 1275Cashier Employment差分约束系统的建立和求解) Cashier Employment Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 7569   Accepted: 2856 Description A sup

ACMer' 1576

POJ 1275 Cashier Employment(差分约束系统)

摘自冯威论文——《数与图的完美结合》设num[ i ]为i时刻能够开始工作的人数,x[ i ]为实际雇佣的人数,那么x[ I ]设r[ i ]为i时刻至少需要工作的人数,于是有如下关系:    x[ I-7 ]+x[ I-6 ]+x[ I-5 ]+x[ I-4 ]+x[ I-3 ]+x[ I-2 ]+x[ I-1 ]+x[ I ]>=r[ I ] 设s[ I ]=x[ 1 ]+x[ 2 ]…+x[ I ],得到    0    s[ I ]-s[ I-8 ]>=r[ I ], 8    s[ 23 ]+s

Czy 2250

POJ1275-Cashier Employment差分约束系统

正题 题目链接:http://poj.org/problem?id=1275 题目大意 1∼241\sim 241∼24小时中第iii个小时需要rir_iri​个出纳员 有nnn个人应聘,第iii从xix_ixi​开始工作,一直工作8个小时。 求至少要招募多少人应聘。 解题思路 numinum_inumi​表示第iii个小时有多少人招聘。 设定kik_iki​表示第iii个小时放多少人 这时需...

QuantAsk 518

poj 1275--Cashier Employment差分约束系统

题目描述德黑兰的一家每天24小时营业的超市,需要一批出纳员来满足它的需求。超市经理雇佣你来帮他解决一个问题————超市在每天的不同时段需要不同数目的出纳员(例如,午夜只需一小批,而下午则需要很多)来为顾客提供优质服务,他希望雇佣最少数目的纳员。 超市经历已经提供一天里每一小时需要出纳员的最少数量————R(0),R(1),…,R(23)。R(0)表示从午夜到凌晨1:00所需

Sdywolf的博客 714

POJ 1275-Cashier Employment(差分约束系统)

题目地址:POJ 1275 题意:给出一个超市24小时各须要R[i]个雇员工作,有N个雇员能够雇佣。他们開始工作时间分别为A[i],求须要的最少的雇员人数。 思路:这个题的查约束太多了!简直是差评!只是也不是否能定这是道好题。 设dis[i]为0-i小时内工作的人数(dis[24]即为所求)。r[i]为第(i-1)-i小时时须要在工作的人数,t[i]能够在第i-1小时開始...

aoe41606的博客 139

POJ 1275 Cashier Employment 出纳员问题 差分约束系统

题目: Tehran 的一家每天24 小时营业的超市,需要一批出纳员来满足它的需要。超市经理雇 佣你来帮他解决他的问题——超市在每天的不同时段需要不同数目的出纳员(例如:午夜时 只需一小批,而下午则需要很多)来为顾客提供优质服务。他希望雇佣最少数目的出纳员。 经理已经提供你一天的每一小时需要出纳员的最少数量——R(0), R(1), ..., R(23)。 R(0)表示从午夜到上午1:0

李佩爽的博客 1327

Cashier Employment poj 1275 差分约束系统

题目大意Tehran 的一家每天24 小时营业的超市,需要一批出纳员来满足它的需要。超市经理雇佣你来帮他解决他的问题——超市在每天的不同时段需要不同数目的出纳员(例如:午夜时只需一小批,而下午则需要很多)来为顾客提供优质服务。他希望雇佣最少数目的出纳员。经理已经提供你一天的每一小时需要出纳员的最少数量——R(0), R(1), …, R(23)。 R(0)表示从午夜到上午1:00 需要出纳员的

A_loud_name 672

[POJ 1275] Cashier Employment 差分约束系统

题目传送门:【POJ 1275】题目大意: (摘自 http://blog.csdn.net/wangjian8006/article/details/7956356)德黑兰的一家每天24小时营业的超市,需要一批出纳员来满足它的需求。超市经理雇佣你来帮他解决一个问题————超市在每天的不同时段需要不同数目的出纳员(例如,午夜只需一小批,而下午则需要很多)来为顾客提供优质服务,他希望雇佣最少数目的纳员

江澤妮可 634

POJ 1275 Cashier Employment(差分约束系统+二分)

题意:一家店给出每个时间段(0:00 - 23:00)需要的员工数,再给出n个员工的申请雇佣时间段,每一个员工可以连续工作8小时,问一天最少需要雇佣多少员工 思路:设di : 开始到第i时间刻雇佣的人数一共多少人,则有: 0 d[i] - d[i - 8] >= R[i]  (i >= 8 时) d[i] - d[i + 16] >= R[i] - answer (i d[24] -

hnust_Derker的博客 408

POJ 1275 二分 + 差分约束系统

题意 传送门 POJ 1275 Cashier Employment 题解 不等式问题,考虑转化为差分约束系统。某个时刻 iii 的工作人数为前 888 个小时内开始工作的人数和,将其转化为前缀和 SSS 的差分。设 num[i]num[i]num[i] 为工作开始时间为时刻 iii 的人数。 {S[i]≥S[i−1]S[i]−S[i−1]≤num[i]S[i]−S[j]≥{R[i]i>jR[i]−(S[23]−S[−1])i<j,j=(i−8+24)mod  24\begin{cases} S

neweryyy的博客 183

POJ1275 Cashier Employment[差分约束系统 || 单纯形法]

Cashier Employment Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 7997   Accepted: 3054 Description A supermarket in Tehran is open 24 hours a day every day a...

weixin_33970449的博客 120

poj1275 Cashier Employment 差分约束

poj1275 Cashier Employment 题目传送 sol: 不是很容易想到。。 不妨令\(S[i](0≤i≤23)\)表示前i小时已经定了i个人。 那么根据题目给定条件及隐含条件作出约束: \[ s[i]-s[i-8]≥need[i]\ (8≤i≤23)\\ sum-(s[i+16]-s[i])≥need[i]\ (0≤i≤7)\\ s[i-1]≤s[i]\ (0≤i≤23...

weixin_30608131的博客 182

图论(差分约束系统):POJ 1275 Cashier Employment

Cashier Employment Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 7651 Accepted: 2886 Description A supermarket in Tehran is open 24 hours a day every day a...

weixin_30293135的博客 72

POJ 1275 Cashier Employment 较难的差分约束

题目大意:一个售货店需要招人,每一个小时至少应该有Ri个售货员,一共有24个小时,一共N个人来应聘 并且每个来应聘的人能从Ti工作到Ti+8(对于超过23的,从1算起)问最少聘用多少人? emmmm这题我感觉基本是个神题,靠本蒟蒻的脑子是想不出来的 于是看了看这位大佬的题解https://blog.csdn.net/zhang20072844/article/details/7816105 大概是...

InverseDZY的博客 261

poj1275 Cashier Employment (差分约束)

题意: 一家24小时营业的超市,需要雇佣一些出纳员来满足需求。超市在不同时刻需要不同数目的出纳员,记为ri (0 有n个人来申请职位,一旦雇佣一个人,他将从一个时刻ti开始,连续工作8小时。 输入ri和ti,求满足需求最少需要雇佣多少人。 思路: 设r[i]为每小时需要的出纳员数目, t[i]为每小时应征者的数目, s[i]为从时刻0到时刻i雇佣的出纳员总数, sum为雇佣的所有

Shion的专栏 640
上一篇: UVA 11478V Halum 二分答案+差分约束系统
下一篇: 扩欧——NKOJ P3677 观光车
INCINCIBLE
博客等级 码龄11年 31粉丝 195原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值