福大OJ 招聘

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/IoT_fast/article/details/85090042

Description

Alice新开了一家公司,它的下面有两个项目,分别需要N1和N2个人来完成。现在有N个人前来应聘,于是Alice通过面试来决定他们中的哪些人会被录用。

Alice在面试中,会仔细考察他们能如何为公司的项目带来收益。她给每个人打了两个分值Q1和Q2,表示他加入第一个和第二项目分别能带来的收益值。同时,她也会仔细考察他们每个人的缺点,并且给每人打了另两个分值C1和C2,表示他们进入每个项目可能带来的负面效应。Alice心目中的最优决策是,在决定好录用哪些人以及每个人在哪个项目下工作之后,他们为公司带来的收益总和,除以他们为项目带来的负面效应总和,这个比值要最大。你能帮他计算出在最优决策下,这个比值为多少吗?

前来应聘的人数总是大于等于两个项目需求人数的总和,因此Alice一定会恰好招N1+N2个人,分配给第一个项目N1个人,分配给第二个项目N2个人,没有人会同时属于两个项目。

Input

输入文件包含多组测试数据。 第一行,给出一个整数T,为数据组数。接下来依次给出每组测试数据。 每组数据第一行为三个用空格隔开的整数N,N1,N2,表示前来应聘的人数,以及两个项目分别需要的人数。 接下来N行,每行是用空格隔开的四个整数Q1,C1,Q2,C2,依次表示每个人在第一个项目下的价值和负面效应,以及第二个项目下的价值和负面效应。 T ≤ 100 1 ≤ Q1, Q2 ≤ 2000 1 ≤ C1, C2 ≤ 50 0 < N1 + N2 ≤ N ≤ 50,

Output

对于每组测试数据,输出一行"Case #X: Y",其中X表示测试数据编号,Y表示最优决策下招募的人的价值总和与负面效应总和的比值,与正确答案的绝对误差不应超过10-6(其中表示次方,如:10^-6表示10的-6次方)。所有数据按读入顺序从1开始编号。

Sample Input 1

1
5 2 2
12 5 8 3
9 4 9 4
7 3 16 6
11 5 7 5
18 10 6 3

Sample Output 1

Case #1: 2.444444

源码

参考博客
用一个三阶的动态规划来做,dp[i][j][k]代表前i个人分j个人去做项目1,k个人去做项目2,具体解析看代码注释

#include <iostream>
#include <fstream>
#include <cstring>
#include <stdio.h>
#include <cmath>

using namespace std;

//前i个人j个人去做项目1,k个人去做项目2
//值为正面效益总和减去效益比乘上负面效应总和,若大于0则效益比要增大,小于0效益比要减小 
//从而通过二分法来找出误差足够小的那个效益比 
double dp[55][55][55];  

struct person{
	double q1,q2,c1,c2;
}; 

person data[55];
int n,n1,n2;

bool isok(double r)
{
	for(int i=1;i<=n;i++)
		for(int j=0;j<=n;j++)
			for(int k=0;k<=n;k++)
			{
				if(j+k>i) break;
				dp[i][j][k]=dp[i-1][j][k];  //初始化为第i个人不录用
				if(j==0&&k==0) ;
				else if(j==0) dp[i][j][k]=max(dp[i][j][k],dp[i-1][j][k-1]+data[i].q2-data[i].c2*r);
				else if(k==0) dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-1][k]+data[i].q1-data[i].c1*r);
				else 
				{
					//看是把第i个人安排去项目1值大还是项目2 
					dp[i][j][k]=max(dp[i][j][k],dp[i-1][j][k-1]+data[i].q2-data[i].c2*r);
					dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-1][k]+data[i].q1-data[i].c1*r); 
				}
			}
	if(dp[n][n1][n2]>0.0) return true;
	else return false;
} 

int main()
{
	freopen("input/employee.txt","r",stdin);
	int t;
	cin>>t;
	for(int cas=1;cas<=t;cas++)
	{
		cin>>n>>n1>>n2;
		memset(dp,0,sizeof(dp));
		for(int i=1;i<=n;i++)
		{
			cin>>data[i].q1>>data[i].c1>>data[i].q2>>data[i].c2;
		} 
		for(int i=0;i<55;i++)
			for(int j=0;j<55;j++)
				for(int k=0;k<55;k++)
					dp[i][j][k]=-999999.0;  //初始化
		dp[0][0][0]=0.0;
		double l=0.0,r=2000.0;  //二分找出误差足够小的效益比 
		while(r-l>0.000001) 
		{
			double mid=(r+l)/2.0;
			if(isok(mid)) l=mid;  //说明效益比小了,所以dp>0.0,效益比要增大 
			else r=mid;
		}
		printf("Case #%d: %.6lf\n",cas,l);  //必须是l,因为是r减去l的误差小于0.000001 
	} 
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/IoT_fast/article/details/85090042