本题用到贪心策略和结构体排序。
问题简化:现有资本M,N个房间,第i个房间对应着价格为F[i]和收益J[i],需要将M全部花光去投资每个房间,使得收益最大,从每个房间中获取的效益与投入成正比,求最大获益。
贪心策略:由于成正比,收益与投资成正比,所以可以考虑“性价比”这个概念,把每个房间当作一个商品,则该商品的性价比=收益/价格,然后按照性价比从大到小排序,然后将资本M按顺序投资到每个房间,直到M为0或全部投资完。
将每个房间作为一个结构体变量,结构体含有数据成员:收益J和价格F。如何对结构体进行排序?只需要定义两个结构体是如何比较大小的即可,即需要说明:对结构体而言,>和<等不等符号分别是什么意思,因而要用到运算符重载。此处是按照 J/F的大小排序的,所以F不能为0,事实上,题目没有限制F是否为0,所以需要考虑F=0的情况。下面来看如何定义两个房间的大小关系的,用于运算符 > 的重载。
房间R1和R2:
R1.F=0且R2.F=0,这意味着,二者价格均为0,所以定义谁的收益大,谁就大。
R1.F!=0且R2.F=0,这意味着R2价格为0,所以定义R2大。(有可能R1和R2的收益均为0,那么二者就相等了,但实际投资过程中,当然不会投资R1和R2,所以定义R2比R1大还是相等不重要)
R1.F=0且R2.F!=0,这意味着R1价格为0,所以定义R1大。
R1.F!=0且R2.F!=0,这种情况,直接按照J/F定义R1和R2的大小即可。
用Dev-C++编写的C++代码:(提交之后AC)
#include <iostream> #include <iomanip> using namespace std; struct Room //定义结构体 { double J,F;//两个数据成员 Room(double j=0.0,double f=0.0) //构造函数,最好带有默认形参 { J = j; F = f; } void setRoom(double j,double f) //用于给结构体变量的两个数据成员赋值的函数 { J = j; F = f; } bool operator > (Room room) //运算符 > 的重载 { if (F==0 && room.F==0) return J > room.J; //都为0 else if(F==0 && room.F!=0) return 1; else if(F!=0 && room.F==0) return 0; else return (J/F) > (room.J/room.F); //都不为0 } }; void BinSort(Room *R,int N) //折半插入排序 { for(int i=1;i<N;i++) { int low=0,high=i-1,mid; while(low<=high) { mid = (low+high) / 2; if(R[i]>R[mid]) //此处用到了结构体之间 > 的关系,如果没有运算符 > 的重载会报错,这里用 > 而不用 < 使得排序是按照从大到小排序的 high = mid - 1; else low = mid + 1; } Room temp = R[i]; //这里用到结构体自带的赋值运算符,不用重载 for(int j=i;j>low;j--) R[j] = R[j-1]; R[low] = temp; } } int main() { int M,N,k=0,kk=0; double J,F; double result[1000]; //存储最终结果 while(1) { cin >> M >> N; if(M==-1 && N ==-1) break; else { double tot = 0.0; //用于记录结果,每次清零 Room *R = new Room[N]; //针对每组数据,开N个房间 for(int i=0;i<N;i++) //输入每个房间的两个参数,收益J和价格F { cin >> J >> F; R[i].setRoom(J,F); } BinSort(R,N); //排序 for(int j=0;j<N && M>0 ;j++) //逐个投资,直到投资完所有房间或者资本花光 { // 遇到第i个房间的两种可能情况 if(M>=R[j].F) //一:资本足够 { M -= R[j].F; // 花掉了所需价格的资本 tot += R[j].J; // 获得的对应的全部收益 } else //二:资本不够 { M = 0; //资本花光 tot += M/R[j].F*R[j].J; //按正比收益一部分 } } result[k++] = tot; // 记录结果 } } for(int i=0;i<k;i++) cout << setprecision(3) << fixed << result[i] << endl; return 0; }
说明:
1.如对折半插入排序算法有疑问,可以参考:
http://blog.csdn.net/ten_sory/article/details/51731823
2.在C++中将结果保留三位小数的方法,需要加载头文件#include<iomanip>,代码是:cout << setprecision(3) << fixed << 3.1415926 << endl;
如有纰漏,欢迎指正!