蓝桥杯:试题 算法训练 Remember the A La Mode

蓝桥杯:试题 算法训练 Remember the A La Mode

资源限制
时间限制:1.0s 内存限制:256.0MB

问题描述
  Hugh Samston经营着一个为今年的ICPC世界总决赛的参与者提供甜点的餐饮服务。他将会提供上面有冰激凌的饼片。为了满足不同的需求,他准备了许多不同的饼片和冰激凌。
  Hugh希望以一份饼片上一份冰激凌的方式来提供甜点。然而,作为一个商人,他希望能赚到尽可能多的钱。他知道不同种类的饼片和冰激凌组合的价格,也知道那些冰激凌和那些饼片不能组合在一起。
  Hugh想根据每种饼片和冰激凌的数量,以及之前提到的不同组合的情况,确定他能获得的利润的范围。
  
输入格式
  测试数据的输入一定会满足的格式。
  输入的第一行包含两个整数P, I,分别表示饼片和冰激凌的种类数。
  接下来一行包含P个整数,表示每种类型饼片的数量。
  接下来一行包含I个整数,表示每种类型冰激凌的数量。
  接下来P行,每行包含I个实数,表示每种类型饼片和冰激凌组合的结果。
  如果这种饼片和这种冰激凌可以组合,则为一个(0,10)的实数,表示这种组合的收益。
  否则,则为-1,表示这两种之间不能组合。
  
输出格式
  输出一行,以"(最小收益) to (最大收益)"的方式输出利润的范围。

请注意:所有的饼片和冰激凌都必须用完。
  
样例输入
2 3
40 50
27 30 33
1.11 1.27 0.70
-1 2 0.34

样例输出
91.70 to 105.87

数据规模和约定
  0 < P,I <= 50,每种类型饼片或冰激凌数量不超过100。

#include 
#include 
#include 
#include 
using namespace std;
int p,l;//p为饼干的种类,l为冰淇淋的种类
int pp[101],ll[101];//存放饼干和冰淇淋每种种类的数量 
int ppp[101],lll[101];//保存复制pp和ll数组,二次使用
double income[101][101];//收益情况
double temp[101][101];//用来记录收益的高低 
int zuo = 0,you =0;//下标

//初始化数据
void init(){
	cin>>p>>l;
	for(int i =1;i <= p;i++){
		cin>>pp[i];
		ppp[i] = pp[i];
	}
	for(int j =1;j <= l;j++){
		cin>>ll[j];
		lll[j] = ll[j];
	}
	for(int k =1;k <= p;k++){
		for(int h = 1;h <= l;h++){
			cin>>income[k][h];
			
		}
	}
	for(int k =1;k <= p;k++){
		for(int h = 1;h <= l;h++){
			
			temp[k][h] = -1;
		}
	}
	int t;
	int time = p*l;
	/*为利润的高低标记排名,利润最高的为1,次之为2(如果利润相等,也不影响前后顺序),以此类推*/
	for(int y = 1;y <= time;y++){
		double max = -2;
		int left = 0,rigth = 0;
		//设立一个未标记数为最大值 
		for(int s =1;s <= p;s++){
			if(max != -2) break;
			for(int d = 1;d <= l;d++){
			   if(temp[s][d] == -1 && income[s][d] != -1){
			   		max = income[s][d];
			   		left = s;
					rigth = d; 
			   		break;
			   }  
				
			}
		}
		for(int k =1;k <= p;k++){
			for(int h = 1;h <= l;h++){
				//当收益为0时,不取该组合,因此标记该组合为0 
				if(income[k][h] == -1 &&  temp[k][h] == -1){
					temp[k][h] = 0;
				}
				//查找当前未标记数中的最大收益值 
				else if(max <= income[k][h] && temp[k][h] == -1){
					max = income[k][h];
					left = k;
					rigth = h;
				} 				
			}
		}
		temp[left][rigth] = y; 
	} 
} 
//查询值为i的下标 
void find_xiabiao(double temp[][101],int i){
	zuo = 0,you =0;
	for(int k =1;k <= p;k++){
		if(zuo != 0 && you != 0) break;
		for(int h = 1;h <= l;h++){
			if(temp[k][h] == i){
				zuo = k;
				you = h;
				break;
			}
			
		}
	}
}

double find_max(){
	double sum = 0;
	for(int i = 1; i <= p*l;i++){
		find_xiabiao(temp,i); //获得下标索引
		if(pp[zuo] >=  ll[you] && pp[zuo]!= 0 &&ll[you]!= 0){
			sum += ll[you]*income[zuo][you];
			pp[zuo] -= ll[you];
			ll[you] -= ll[you];
		}else if(pp[zuo] <=  ll[you] && pp[zuo]!= 0 &&ll[you]!= 0){
			sum += pp[zuo]*income[zuo][you];
			pp[zuo] -= pp[zuo];
			ll[you] -= pp[zuo];
		}
	}
	return sum;
}
double find_min(){
	double sum = 0;
	for(int i = p*l; i >= 1;i--){
		find_xiabiao(temp,i);//获得下标索引 
		if(zuo == 0 && you == 0) continue;		
		if(ppp[zuo] >=  lll[you] && ppp[zuo]!= 0 &&lll[you]!= 0){
			sum += lll[you]*income[zuo][you];
			ppp[zuo] -= lll[you];
			lll[you] -= lll[you];
		}else if(ppp[zuo] <=  lll[you] && ppp[zuo]!= 0 &&lll[you]!= 0){
			sum += ppp[zuo]*income[zuo][you];
			ppp[zuo] -= ppp[zuo];
			lll[you] -= ppp[zuo];
		}
	}
	return sum;
}
int main()
{
	init();
	cout<<setiosflags(ios::fixed)<<setprecision(2);
	cout<<find_min()<<" "<<"to "<<find_max();
	 
    return 0;
}


蓝桥杯:试题 算法训练 Remember the A La Mode_第1张图片

说明:
①输入数据
②将利润值得大小进行标记,-1得标为0,不考虑他得计算。接下来根据利润从高到低得顺序标记,从1开始标记,如果有利润得值相同,则连续标记即可。
③根据标记进行计算,求最高值时,从标记1开始计算;求最低值时从标记号最大得数开始计算

本作者的这个方法还是有一定的局限性,所以未能取得100分,但是该方法还是可以值得参考思考下

你可能感兴趣的:(蓝桥杯)