1. 程式人生 > >優先佇列 (結構體自定義比較)(過載函式)(大集合)

優先佇列 (結構體自定義比較)(過載函式)(大集合)

之前一直在 用 sort 的結構體自定義函式,感覺到 STL 強大,今天刷題遇見優先佇列 的題 ,要求跟 以前一樣,資料量大,要求對某個資訊排序,並且 做相應的 操作,如果用 普通的結構體來模擬 ,但是這個sort 要每次插進結構體陣列,都要排序一遍,耗時很大,不如用一個 優先佇列,和過載函式,插進去一個,就會自動的去排序,不用再一遍一遍的 去 sort 排序。

如何用過載函式?(由於能力有限)

1.直接上程式碼:

#include<stdio.h>
#include<iostream>
using namespace std;
#include<queue>
typedef struct node
{
	int num;
	friend bool operator < (struct node a,struct node b) 
	{
		return a.num>b.num;
	}
}point;

這個 friend bool operator 好像只能在 結構體裡面 使用,並且 後面 的引數 要兩個,寫一個 會報錯。

 把 那個 struct 改為 const ,也是對的,

2.

#include<stdio.h>
#include<iostream>
using namespace std;
#include<queue>
typedef struct node
{
	int num;
	bool operator < (const node& b) const 
	{
		return num>b.num;
	}
}point;

用 bool operator ,就需要 在後面 加上一個 const ,在結構體裡面,後面的 引數 只能是一個。

3.

#include<stdio.h>
#include<iostream>
using namespace std;
#include<queue>
typedef struct node
{
	int num;
	
}point;

bool operator < (const node& a,const node & b) 
{
	return a.num>b.num;
}

或者直接  就可以。

bool operator < (point a,point b)

來看看題:

題面:看病要排隊 HDU - 1873

看病要排隊這個是地球人都知道的常識。
不過經過細心的0068的觀察,他發現了醫院裡排隊還是有講究的。0068所去的醫院有三個醫生(汗,這麼少)同時看病。而看病的人病情有輕重,所以不能根據簡單的先來先服務的原則。所以醫院對每種病情規定了10種不同的優先順序。級別為10的優先權最高,級別為1的優先權最低。醫生在看病時,則會在他的隊伍裡面選擇一個優先權最高的人進行診治。如果遇到兩個優先權一樣的病人的話,則選擇最早來排隊的病人。

現在就請你幫助醫院模擬這個看病過程。

Input

輸入資料包含多組測試,請處理到檔案結束。
每組資料第一行有一個正整數N(0<N<2000)表示發生事件的數目。
接下來有N行分別表示發生的事件。
一共有兩種事件:
1:"IN A B",表示有一個擁有優先順序B的病人要求醫生A診治。(0<A<=3,0<B<=10)
2:"OUT A",表示醫生A進行了一次診治,診治完畢後,病人出院。(0<A<=3)

Output

對於每個"OUT A"事件,請在一行裡面輸出被診治人的編號ID。如果該事件時無病人需要診治,則輸出"EMPTY"。
診治人的編號ID的定義為:在一組測試中,"IN A B"事件發生第K次時,進來的病人ID即為K。從1開始編號。

Sample Input

7
IN 1 1
IN 1 2
OUT 1
OUT 2
IN 2 1
OUT 2
OUT 1
2
IN 1 1
OUT 1

Sample Output

2
EMPTY
3
1
1

這道題 就需要 用到優先佇列(可以用三個優先佇列),(也可以用一個佇列陣列),我用的是佇列陣列。

如果優先順序不同,就按優先順序從高到低 來看病,如果不是 ,就按來的先後 來看病,典型的 優先佇列(過載來做)

程式碼:

#include<iostream>
#include<string.h>
#include<algorithm>
#include<stdio.h>
#include<queue>
using namespace std;
const int maxn = 2001;
struct node
{
	int jishu;
	int k;
	bool operator<(const node &b) const
        {
                if ( jishu == b.jishu)
                        return k > b.k;
                return jishu < b.jishu;
        }
};

int main()
{
	int i;
	char zhiling[maxn];
	int n;
	while (cin >> n)
	{
		priority_queue<node>s[maxn];
		int count = 1;
		while (n--)
		{
			memset(zhiling, 0, sizeof(zhiling));
			cin >> zhiling;
			if (zhiling[0] == 'I')
			{
				struct node q;
				q.k = count++;
				int ysnum;
				cin >> ysnum >> q.jishu;
				s[ysnum].push(q);
			}
			else
			{
				int ysnum2;
				cin >> ysnum2;
				if (s[ysnum2].size() == 0)
					cout << "EMPTY" << endl;
				else
				{
					cout << s[ysnum2].top().k << endl;
					s[ysnum2].pop();
				}
			}
		}
		
	}
	return 0;
}

一開始 沒有按照 先來的順序,就WA 了好幾發。

2.Windows Message Queue HDU - 1509

題面:

訊息佇列是Windows系統的基本基礎。對於每個程序,系統都維護一個訊息佇列。如果此過程發生某些事情,例如滑鼠單擊,文字更改,系統將向佇列新增訊息。同時,如果該佇列不為空,則該程序將根據優先順序值從佇列中獲取訊息。請注意,優先順序較低的值意味著較高的優先順序。在此問題中,系統會要求您模擬訊息佇列,以便將訊息放入訊息佇列並從訊息佇列中獲取訊息。
輸入
輸入中只有一個測試用例。每一行都是一個命令,“GET”或“PUT”,這意味著獲取訊息或傳送訊息。如果命令是“PUT”,則只有一個字串表示訊息名稱,兩個整數表示引數和優先順序後跟。最多將有60000個命令。請注意,一條訊息可以出現兩次或更多次,如果兩條訊息具有相同的優先順序,則首先處理一條訊息(即,具有相同優先順序的FIFO)。處理到檔案結尾。
輸出
對於每個“GET”命令,輸出從訊息佇列中獲取的命令,其中名稱和引數在一行中。如果佇列中沒有訊息,則輸出“EMPTY QUEUE!”。 “PUT”命令沒有輸出。

Sample Input

GET
PUT msg1 10 5
PUT msg2 10 4
GET
GET
GET

Sample Output

EMPTY QUEUE!
msg2 10
msg1 10
EMPTY QUEUE!

程式碼:

#include<iostream>
#include<string.h>
#include<algorithm>
#include<stdio.h>
#include<queue>
const int maxn=60005;
using namespace std;
typedef struct node
{
	char zifu[20];
	int num;
	int ji;
	int id; 
	bool operator < (const node& b) const  
	{
		if(ji!=b.ji)
			return ji>b.ji;
		return id>b.id;
	}  
}point;





char zhiling[maxn];


int main()
{
	priority_queue<point>s;
	int i=0;
	int count=1;
	while(cin>>zhiling)
	{
		if(zhiling[0]=='G')
			{
				if(!s.empty())
					{
						point q;
						q=s.top();
						s.pop();
						cout<<q.zifu<<' '<<q.num<<endl;
					}
				else
					cout<<"EMPTY QUEUE!"<<endl;
			}
		else
		{
			point zhilinga;
			zhilinga.id=count++;
			cin>>zhilinga.zifu>>zhilinga.num>>zhilinga.ji;
			s.push(zhilinga);
		}	
		
			
	}	
	return 0;
}

也是對優先順序的考慮。

3.Stones  HDU - 1896

題面 :

因為自行車的位置不對,塞姆普開始每天早上從東到西步行,每天晚上步行回來。散步會引起疲勞,所以這次塞姆普總是在路上玩一些遊戲。
路上有很多石頭,當他遇到一塊石頭時,如果碰到的是第奇數個的石頭,他會盡可能地把它扔到前面;如果碰到的是第偶數個的石頭,他會把它留在原處。現在給您一些關於路上石頭的資訊,您要告訴我從起點到塞姆普路過的最遠石頭的距離。請注意,如果兩個或更多的石頭停留在同一位置,您將首先遇到較大的(具有最小Di的,如輸入中所述)。

Input

在第一行中,有一個整數T(1<=T<=10),它表示輸入檔案中的測試用例。
然後是T個測試用例。對於每個測試用例,我將在第一行中給出整數N (0<=N<=100000),這意味著路上的石頭數量。然後是N行,行中有兩個整數Pi(0<=Pi<=100000)和Di(0<=Di<=1000),這意味著第i個石頭的位置以及塞姆普可以把它扔多遠。

Output

個測試用例輸出一行,如描述所述。

Sample Input

2
2
1 5
2 4
2
1 5
6 6

Sample Output

11
12

程式碼:

#include<iostream>
#include<string.h>
#include<algorithm>
#include<stdio.h>
#include<queue>
using namespace std;
const int maxn=100005;
typedef struct node
{
	int weizhi;
	int di;
	bool operator < (const node& b )const
	{
		if(weizhi==b.weizhi)
			return di>b.di;
		return weizhi>b.weizhi;	
	}
	
}point;
priority_queue<point>s;

int main()
{
	int i=0;
	int t;
	cin>>t;
	int tonenum;
	while(t--)
	{
		i=0;
		cin>>tonenum;
		for(i=0;i<tonenum;i++)
			{
				point p;
				cin>>p.weizhi>>p.di;
				s.push(p);
			}
			int bushu=1;
			int maxjuli=0;
		while(!s.empty())
			{
				if(bushu%2!=0)
					{
						bushu=!bushu;
						point q;
						q=s.top();
						s.pop();
						i=q.weizhi;
						q.weizhi+=q.di;
						s.push(q);
						maxjuli=q.weizhi;	
					}
				else
				{
					i=s.top().weizhi;
					s.pop();
					bushu=!bushu;
				}
			}
	
		cout<<maxjuli<<endl;
	}
		
		
	return 0;
}

先是 把所有的 石頭的位置 和優先順序 插入優先度列。

在這裡 ,每遇見 一個 石頭 ,就要判斷 這個石頭 是否是偶數次,如果是,那就把它從優先佇列中彈出,如果不是,就把他扔後位置 更新插入優先佇列 。因為是自動排序的,所以只要控制好奇數和偶數就行,我用了個開關0和1,不斷取非,就能 集合偶相互轉化,什麼時候 是結束呢?那就是 優先佇列 裡面 沒有元素的時候,就 結束了,題目說的是,不能再 經過 奇數 石頭。那怎麼 來計算 最大的距離,每次扔石頭時,就用maxjuli來記錄位置,這個題,真是有點意思,就是 你扔的 沒有 佇列裡面 後面一個遠, 下次 走到 這個 石頭時(這時就是偶數),就把他彈出。如果扔的比佇列後面一個元素的位置遠,走到下一個時,(因為他這是偶數)所以直接彈出。如果後面 沒有元素了,那這個 就是最遠的;如果還有元素,就把下面一個 扔的位置,在記錄下來,最後的結束是空佇列,所以說,最後一個 扔的是最遠的。

看看 圖解

應該就是這樣 。

加油 。。