1. 程式人生 > >201412-3集合競價

201412-3集合競價

問題描述

試題編號: 201412-3
試題名稱: 集合競價
時間限制: 1.0s
記憶體限制: 256.0MB
問題描述:

問題描述

  某股票交易所請你編寫一個程式,根據開盤前客戶提交的訂單來確定某特定股票的開盤價和開盤成交量。
  該程式的輸入由很多行構成,每一行為一條記錄,記錄可能有以下幾種:
  1. buy p s 表示一個購買股票的買單,每手出價為p,購買股數為s。
  2. sell p s 表示一個出售股票的賣單,每手出價為p,出售股數為s。
  3. cancel i表示撤銷第i行的記錄。
  如果開盤價為p0,則系統可以將所有出價至少為p0的買單和所有出價至多為p0的賣單進行匹配。因此,此時的開盤成交量為出價至少為p0的買單的總股數和所有出價至多為p0的賣單的總股數之間的較小值。
  你的程式需要確定一個開盤價,使得開盤成交量儘可能地大。如果有多個符合條件的開盤價,你的程式應當輸出最高的那一個。

輸入格式

  輸入資料有任意多行,每一行是一條記錄。保證輸入合法。股數為不超過108的正整數,出價為精確到恰好小數點後兩位的正實數,且不超過10000.00。

輸出格式

  你需要輸出一行,包含兩個數,以一個空格分隔。第一個數是開盤價,第二個是此開盤價下的成交量。開盤價需要精確到小數點後恰好兩位。

樣例輸入

buy 9.25 100
buy 8.88 175
sell 9.00 1000
buy 9.00 400
sell 8.92 400
cancel 1
buy 100.00 50

樣例輸出

9.00 450

評測用例規模與約定

  對於100%的資料,輸入的行數不超過5000。

 

        本題可以將股票的買賣資料存到結構體中,再將購入股票的記錄和銷售股票的記錄分別存到兩個優先佇列中,購入股票的佇列的優先順序按價格從大到小排列,銷售股票的佇列的優先順序按價格從小到大排列。再進行競價處理,每次分別取購買和銷售佇列中優先順序最高的一個記錄,對他們的數量進行判斷,如果購買的數量多,則銷售記錄可以刪除,並將購買數量減掉銷售數量;若銷售數量大,則將購買記錄刪掉,並將銷售數量減掉購買數量程式碼如下:

#include<iostream>
#include<queue>
#include<string.h>
#define max 5000 
using namespace std;
struct trading
{
	int orderno;	//交易號 
	char t;		//標記此次交易是購買還是銷售 
	float price;	//價格 
	long long quantity;		//本次交易的數量 
	bool operator < (const trading& n) const	//過載運算子,用來設定佇列的優先順序 
	{ 
		if(t=='s')		
			return price>n.price;
		else
			return price<n.price;
	}
};
bool cancel[max+1];		//標記交易是否取消 
int main()
{
	trading t;
	priority_queue<trading> sell,buy; 
	string strading;
	memset(cancel,false,sizeof(cancel));
	int no=0,tno;
	while(cin>>strading)
	{
		//如果輸入的是取消記錄 ,則設定取消標誌 
		if(strading[0]=='c')
		{
			no++;
			cin>>tno;
			cancel[tno]=true;
		}
		else if(strading[0]=='b' || strading[0]=='s')
		{
			//設定交易號 
			no++;
			t.orderno=no;
			//設定交易方式 
			t.t=strading[0];
			//輸入價格和數量 
			cin>>t.price>>t.quantity;
			//分別各自的優先佇列中 
			if(strading[0]=='s')
				sell.push(t);
			else
				buy.push(t);
		}
		else break;
	}
	t.price=0;
	t.quantity=0;
	trading b,s;
	for(;;)
	{
		//將當前佇列中優先順序最高的記錄取出,同時刪除被取消的記錄 
		while(!sell.empty())
		{
			s=sell.top();
			if(cancel[s.orderno])
				sell.pop();
			else break;
		}
		while(!buy.empty())
		{
			b=buy.top();
			if(cancel[b.orderno])
				buy.pop();
			else break;
		}
		//若買賣佇列中有一個為空了則處理結束 
		if(buy.empty() || sell.empty())
			break;
		//處理集合競價
		if(b.price>=s.price)
		{
			//取兩個記錄交易數量的最小值和價格 
			t.quantity+=min(b.quantity,s.quantity);
			t.price=b.price;
			//如果兩個記錄的交易數量相等,則他們互相匹配,都刪除。 
			if(b.quantity==s.quantity)
			{
				buy.pop();
				sell.pop();
			}
			//如果當前的購買數量大於銷售數量,則刪除銷售記錄,並更新購買數量 
			else if(b.quantity>s.quantity)
			{
				b.quantity-=s.quantity;
				buy.pop();
				buy.push(b);
				sell.pop();
			}
			//如果當前的銷售數量大於購買數量,則刪除購買記錄,並更新銷售數量
			else
			{
				buy.pop();
				s.quantity-=b.quantity;
				sell.pop();
				sell.push(s);
			}
		}
		else
			break;
	}
	//輸出結果 
	printf("%.2f",t.price);
	cout<<" "<<t.quantity<<endl;
	return 0;
}