• 【hdoj_1009】FatMouse's Trade


    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1009<

    本题用到贪心策略和结构体排序。

    问题简化:现有资本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;


    如有纰漏,欢迎指正!

  • 相关阅读:
    JSON.parse()与JSON.stringify()的区别
    响应式布局
    document.selection
    jQuery $.proxy() 方法
    <转> 键值表
    jquery-jqzoom 插件 用例
    jquery 笔记
    前端表单验证常用的15个JS正则表达式<转>
    css 问题解决
    <转>break与continue
  • 原文地址:https://www.cnblogs.com/tensory/p/6590798.html
Copyright © 2020-2023  润新知