pku acm 1018

题目: http://poj.org/problem?id=1018


解题报告:

1)方式一(对应maxbp)

分为两个集合S和S1:

1:初始情况下S[ (65535, 0) ], S1 [ ]为空

      输入第一批数据后:(100 25)( 150 35)( 80 25)

     S1为[(100 25)( 150 35)( 80 25)],然后删除S1中不可能为最优解的二值对,即(80 25)得新的S1为[(100 25)( 150 35)]

     令S = S1, S1 为空

2:输入第二批数据(120 80)( 155 40)

     S1为[(100 105)( 100 65)( 120 115) ( 150 75)]删去S1中不可能的最优解二值对,即(100 105)和( 120 115)得到新的S1为[( 100 65) ( 150 75)]

      令S = S1, S1 为空

3:输入第三批数据(100 100 )(120 110)

     得S1为[(100 165)(100 175)(100 175)(120 185)]删去S1中不可能的最优解二值对,即(100 175)得到新的S1为[( 100 165) ( 120 185)]

      令S = S1, S1 为空

4:求最大值,即100/165 与 120/185谁更大??

这一解题思路可以求得最大值,但是一直不能AC,总是超时!!   


2)方式二(对应maxbp2)

参考的是网上的方案,进行枚举

本题中带宽是选取所有设备中的最小值,而价格是选取所有设备的价格总和。如果某个制造商生产的某种设备,它的带宽较高而价格较低,那么选取它的可能性就比较大。再进一步说,如果所选取的n种设备的带宽的最小值b已经确定,那么对于某种设备,我们就可以在那些生产这种设备的,带宽大于等于b的制造商中进行选择。当然是选那个价格最低的设备,因为答案的分子已经确定为b,所以分母越小越好。看来只要枚举b,再对于每个设备贪心的选择最小价格就可以了,时间复杂度为OmnB),B为带宽枚举的数量。但问题又来了,应该怎么枚举带宽,题目中并未给出带宽的取值范围,如果从0..maxB一个一个枚举的话,既费时又会造成过多重复情况(如果枚举那些在输入中出现的两个连续带宽之间的值,最后的答案是一样的)。所以我们应该采取某个方法记录输入中出现过的带宽(STL中的set是个不错的选择),再枚举这些带宽。

顺利AC,这个方法很直接,一次就AC了,数据结构也比较简单。确实比我想的第一种解决方案来的简单。


#include <iostream>
#include <cstdio>
#include <vector>
#include <set>
#include <limits>
#include <algorithm>
#include <list>
#include <iomanip>
using namespace std;

bool mycomp(pair<int,int> p1, pair<int,int> p2)
{
	if(p1.first < p2.first)
		return true;
	if(p1.first > p2.first)
		return false;
	
	if(p1.second < p2.second)
		return false;
	if(p2.second > p2.second)
		return true;
	return false;//相等必须返回true	
}

typedef vector<int>& VIR;
double maxbp(VIR bwidth,VIR price,VIR fnumbers)
{
	double max = 0;
	list<pair<int,int> > s;//price,bandwidth
	list<pair<int,int> > s1;//price,bandwidth
	list<pair<int,int> >::iterator prev,next,pos;
	s.push_back(make_pair<int,int>(0,numeric_limits<int>::max()));
	
	int beg = 0,end = 0;
	for(int i = 0; i < fnumbers.size(); ++i)
	{
		end += fnumbers[i];
		for(int j = beg; j < end; ++j)
		{
			//for(int k = 0; k < sb.size(); ++k)
			for(pos = s.begin(); pos != s.end(); ++pos)
			{
				int b = min(pos->second, bwidth[j]);
				int p = pos->first + price[j];
				s1.push_back(make_pair<int,int>(p,b));					
			}
		}		
		s1.sort(mycomp);		
		prev = next = s1.begin();
		for(++next; next != s1.end(); )
		{		
			if(next->second <= prev->second)
				next = s1.erase(next);
			else
			{
				prev = next;
				++next;
			}
		}
		
		s.swap(s1);
		s1.clear();			

		beg = end;
	}

	
	for(pos = s.begin(); pos != s.end(); ++pos)		
	{
		if(pos->second*1.0/pos->first > max)
			max = pos->second*1.0/pos->first;
	}		
	
	return max;
}

typedef vector<int>& VIR;
double maxbp2(VIR bwidth,VIR price,VIR fnumbers,set<int>& ewidth)
{
	double max = 0;
	int B,P;
	bool bval;
	for(set<int>::iterator pos = ewidth.begin(); pos != ewidth.end(); ++pos)
	{
		B = *pos;
		P = 0;

		int beg = 0,end = 0;
		for(int i = 0; i < fnumbers.size(); ++i)
		{
			int minp = numeric_limits<int>::max();

			end += fnumbers[i];
			bval = false;
			for(int j = beg; j < end; ++j)
			{
				if(bwidth[j] >= B && price[j] < minp)
				{
					minp = price[j];
					bval = true;
				}
			}
			if(bval == false)goto End;
			P += minp;

			beg = end;
		}

		if(B*1.0/P > max)
			max = B*1.0/P;
End:;}

	return max;
}

int main()
{	
	freopen("in.txt","r",stdin);
	
	vector<int> bwidth,price,fnumbers;
	set<int> ewidth;//用于枚举

	int ib,ip;
	int t;
	cin>>t;// 1 <= t <= 10
	while(t--)
	{
		bwidth.clear();
		price.clear();
		fnumbers.clear();

		int n;
		cin>>n;//1 ≤ n ≤ 100
		while(n--)
		{
			int mi;//1 ≤ mi ≤ 100
			cin>>mi;
			fnumbers.push_back(mi);
			while(mi--)
			{
				cin>>ib>>ip;
				bwidth.push_back(ib);
				ewidth.insert(ib);
				price.push_back(ip);
			}
		}

		//cout<<fixed<<setprecision(3)<<maxbp(bwidth,price,fnumbers)<<endl;
		cout<<fixed<<setprecision(3)<<maxbp2(bwidth,price,fnumbers,ewidth)<<endl;
	}	
}


测试数据:

1 3
 3 100 25 150 35 80 25
 2 120 80 155 40
 2 100 100 120 110



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章