poj1275 - Cashier Employment

                                  想看更多的解题报告: http://blog.csdn.net/wangjian8006/article/details/7870410
                                  转载请注明出处:http://blog.csdn.net/wangjian8006

题目大意:
            德黑兰的一家每天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)更多的出纳员在工作
输入描述:
            输入文件的第1行为一个整数T,表示输入文件中测试数据的数目(至多20个)。每个测试数据第一行为24个整数,表示R(0),R(1),...,R(23),R(i)最大可以取到1000。接下来一行是一个整数N,表示申请者的数目,0<=N<=1000。接下来有N行,每行为一个整数ti,0<=ti<=23,测试数据之间没有空行。
输出描述:
           对输入文件中的每个测试数据,输出占一行,为需要雇佣的出纳员的最少数目。如果某个测试数据没有解。则输出"No Solution"。
注:题目描述来自于"图论算法理论、实现及应用"。

解题思路:

           这题太难了,想了半天没有一点思路,剩下半天找资料分析,下面是黑书————《算法艺术与信息学竞赛》

中的描述:

 

 

 还有一些:

 差分约束的关键是 要充分利用所给条件
 建立数组的 逻辑意义 如此题的dis[]数组(s[]数组) 建立差分约束系统即(找出差分约束关系),
 
 
 
 摘自冯威论文——《数与图的完美结合》
 
 
 设num[ i ]为i时刻能够开始工作的人数,x[ i ]为 第 i 时刻实际雇佣的人数,那么x[ I ]<=num[ 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-1 ]<=num[ I ], 0<=I<=23
     s[ I ]-s[ I-8 ]>=r[ I ], 8<=I<=23    建立关系
     s[ 23 ]+s[ I ]-s[ I+16 ]>=r[ I ], 0<=I<=7 建立可以循环的关系
 
     对于以上的几组不等式,我们采用一种非常笨拙的办法处理这一系列的不等式(其实也是让零乱的式子变得更加整齐,易于处理)。首先我们要明白差分约束系统的应用对象(它通常针对多个二项相减的不等式的)于是我们将上面的所有式子都转化成两项未知项在左边,另外的常数项在右边,且中间用>=连接的式子,即:
     s[ I ]-s[ I-1 ]>=0            (0<=I<=23)
     s[ I-1 ]-s[ I ]>=-num[ I ]       (0<=I<=23)
     s[ I ]-s[ I-8 ]>=r[ I ]         (8<=I<=23)
     s[ I ]-s[ I+16 ]>=r[ I ]-s[ 23 ]  (0<=I<= 7)
 
 
 
 论文有点小小的漏洞,也导致了它论文附带的程序是错误的,有BUG
 
 可行方案中还差一个约束条件
 
 S[23] - S[-1] >= sum;sum为雇佣的出纳员总数
 
 
 
 将所有形如 A-B>=C 的式子 我们从节点B 引出一条有向边指向A边的权值为C  (这里注意由于左右确定,式子又是统一的>=的不等式,所以A和B是相对确定的,边是一定是指向A的) ,图就建成了 。
 
 在程序中,我用0作为上面说的-1来构图

注:来自于http://www.cnblogs.com/acSzz/archive/2012/04/29/2476073.html

 

根据这些描述终于把代码调试出来了。...

 

#include <iostream>
using namespace std;
#define MAXT 26
#define MAXE 1000
#define INF INT_MAX

typedef struct{
	int s,t,w;
}Edge;

Edge edge[MAXE];

int r[MAXT];		//某个小时需要多少人
int t[MAXT];		//在第i个小时应聘的人数
int d[MAXT];
int n,edgesum,ans;

void add(int s,int t,int w){
	edge[edgesum].s=s;
	edge[edgesum].t=t;
	edge[edgesum++].w=w;
}

void buildgragh(int x){
	int i;
	edgesum=48;
	for(i=1;i<=16;i++) add(i+8,i,-r[i+8]);
	for(i=17;i<=24;i++) add(i-16,i,x-r[i-16]);
	add(24,0,-x);
}

int bellman_ford(){
	int i,j;
	for(i=0;i<=24;i++) d[i]=INF;
	d[0]=0;
	for(i=0;i<=24;i++){
		for(j=0;j<edgesum;j++){
			if(d[edge[j].s]+edge[j].w<d[edge[j].t]){
				d[edge[j].t]=d[edge[j].s]+edge[j].w;
			}
		}
	}


	for(j=0;j<edgesum;j++){						//判断是否有负环
		if(d[edge[j].s]+edge[j].w<d[edge[j].t]){
			return 0;
		}
	}
	return 1;
}

void Besearch(int low,int high){
	if(low>high) return;
	int mid=(low+high)/2;

	buildgragh(mid);

	if(bellman_ford()){
		ans=mid;
		Besearch(low,mid-1);
	}else{
		Besearch(mid+1,high);
	}
}

int main(){
	int i,Case,x;
	scanf("%d",&Case);
	while(Case--){
		memset(t,0,sizeof(t));
		for(i=1;i<=24;i++) scanf("%d",&r[i]);
		
		scanf("%d",&n);
		for(i=1;i<=n;i++){		//x+1时刻的应聘人数加1
			scanf("%d",&x);
			t[x+1]++;
		}
		edgesum=0;
		for(i=1;i<=24;i++){			//这48条边是固定的,每个图都需要
			add(i-1,i,t[i]);
			add(i,i-1,0);
		}
		ans=-1;						//对人数二分枚举求解
		Besearch(0,n);
		if(ans==-1) printf("No Solution\n");  
        else printf("%d\n",ans);
	}
	return 0;
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值