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



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