现在的位置: 首页 > 综合 > 正文

枚举+贪心+剪枝:POJ_1018 – Communication System

2017年10月27日 ⁄ 综合 ⁄ 共 2738字 ⁄ 字号 评论关闭

题目描述poj1018

主要思路,这位美女大神已经有详细分析并给出代码了。

我这里也提出一点自己的小想法哈(跟上面的前辈有所不同),有待验证。

提炼一下题意:

共有n个devices;

每个device有m个manufactures;

每个manufacture有2个属性:带宽bw和价格pr;

目标是给每个device取一个manufacture(一旦一个device确定了它的manufacture,则这个device的bandwidth和price就被确定为其manufacture的bw和pr),并使全局的B/P的值最大,其中B为n个device中最小的,而P为n个device的price之和。

思路是这样的:【下面提到的B都为全局解的B值】

最优全局解{ B/P }中的“B”无非是所有manufacture的带宽中的某一个值;

那么,我们对所有的manufacture按照bw进行排序得到一个序列tmp[],我们会发现:

              假如B为该序列中的某个,即B = tmp[i],那么其余device的manufacture的bw必须都大于tmp[i],即其余device的manufacture都在i之后; ①

              设总manufacture数为M=Σmi,i=1,2...n;

               我们不需要枚举所有M个B可能的值:

              我们会先得到1个比较弱的结论:B的值不可能取到tmp[M-(n-1)+1],也就是这个下标之后无法提供n个manufacture;②

              再想一个更强的结论:B的值不能比某个device中最大带宽的manufacture的带宽还大。③

              根据结论③,我们可以推出下面一张图,找出一个n个数的序列:max bw of each device;再从这个序列中找出最小的那个MinofMax;假设其在tmp中的位置如下图右所标注;现在证明B可以取到Min Of Max的位置,也就是满足条件③必定满足条件②;也就是MinOfMax后需要提供至少n-1个属于不同device的manufacture,这必定成立,因为如左侧所示,MinOfMax是从n个device中选出来的,至少有n-1个属于不同device的manufacture的bw大于它(也可以有更多的manufacture大于它);

B不能取到Min Of Max之后的位置,因为至少有一个device无法提供比B大的bw。

那能否再缩小枚举的范围呢?答案应该是不能的,因为全局最优解很可能出现在Min of Max的位置,这样下面右侧的两个红色线条应该就可以理解其意义了吧?

综上所述,我们要枚举的部分也就是下图灰色部分。

确定了枚举范围,剩下的事就很好办了,将上图左侧每一行按照price的值升序排列,对于每一个枚举的B,每个device选择manufacture的标准是:bw大于B且price尽可能小,也就是排序后第一个出现的bw大于B的manufacture。

选择好每个device的manufacture之后求一下全局的B/P。枚举完所有可能的B值后选取一个最小的B/P.

下面给出我的代码:

#include <stdio.h>
#include <limits.h>
#include <algorithm>
using namespace std;
#define N 100	//devices num
#define M 100	//each device's manufacture num
#define CMPTYPE_BW 1
#define CMPTYPE_PR 2
typedef struct _manu{
	int bw;
	int pr;
}Manu;
Manu m[N][M];
int d[N];//each device's manufacture number
int type;
bool cmp(Manu a, Manu b){
	if(type == CMPTYPE_BW)
		return a.bw > b.bw;//降序
	else
		return a.pr < b.pr;//升序
}
int main(){
	int t;
	int B,P;
	scanf("%d",&t);
	while(t>0){
		int n,mi;
		int i,j;
		scanf("%d",&n);
		for(i = 0; i < n; i++){
			scanf("%d",&mi);
			d[i] = mi;
			for(j = 0; j < mi; j++){
				scanf("%d%d",&m[i][j].bw, &m[i][j].pr);
			}
		}
		for(i = 0; i < n; i++){//each devices' manufacture sort by bw DESC 
			type = CMPTYPE_BW;
			sort(m[i],m[i]+d[i],cmp);
/*			for(int j = 0; j < d[i]; j++)
			{
				printf("%d ",m[i][j].bw);
			}
			printf("\n");*/
		}
		//get each device's max bw pick the min of those
		int minbwm = INT_MAX;
		for(i = 0; i < n; i++)
			if(m[i][0].bw < minbwm)
				minbwm = m[i][0].bw;
		//printf("%d\n",minbwm);
		for(i = 0; i < n; i++){
			type = CMPTYPE_PR;
			sort(m[i], m[i]+d[i],cmp);
		}
		int tmp[N*M];
		int tmpind = 0;
		for(i = 0;i < n; i++)
			for(j = 0; j < d[i]; j++)
				tmp[tmpind++] = m[i][j].bw;
		sort(tmp,tmp + tmpind);
/*		for(i = 0; i < tmpind; i++)
			printf("%d ",tmp[i]);
		printf("\n");
		for(i = 0; i < n; i++){
			for(int j = 0; j < d[i]; j++)
				{
					printf("%d ",m[i][j].pr);
				}
			printf("\n");
		}*/
		int Blast = -1,P;
		double ratio = -1;
		int pr;
		for(i = 0; tmp[i] <= minbwm; i++){
			B = tmp[i];P = 0;
			if(B == Blast)
				continue;
			for(int k = 0; k < n; k++)
				for(j = 0; j < d[k]; j++)
					if(m[k][j].bw >= B){
						P+=m[k][j].pr;
						break;
					}
			Blast = B;
			if(((double)B/P) > ratio){
				ratio = ((double)B/P);
			}
		}
		printf("%.3f\n",ratio);
		t--;
	}
	//system("pause");
	return 0;
}

抱歉!评论已关闭.