资源限制
时间限制: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;
}
说明:
①输入数据
②将利润值得大小进行标记,-1得标为0,不考虑他得计算。接下来根据利润从高到低得顺序标记,从1开始标记,如果有利润得值相同,则连续标记即可。
③根据标记进行计算,求最高值时,从标记1开始计算;求最低值时从标记号最大得数开始计算
本作者的这个方法还是有一定的局限性,所以未能取得100分,但是该方法还是可以值得参考思考下