NEFU 大一寒假訓練九(優先隊列)2020.02.13

Summary

我太菜了,E 題沒加 endl 就交上去了,真想找塊豆腐撞死 >﹏<
整體來說有一些重複的題,只要讀懂題就不難了
觀察代碼大小也看出來有3個重複題了
在這裏插入圖片描述

Information

No. Title AC/Submit
A 買飯-優先隊列 54/114
B 合併果子-優先隊列 57/104
C 序列合併-優先隊列 23/61
D 合成隕石-優先隊列 48/109
E 堆-優先隊列 45/55
F 瑞瑞的木板-優先隊列 40/107
G 桐桐的新聞系統-優先隊列 27/36

Problem B: 合併果子-優先隊列 (1688) [57/104]

Problem D: 合成隕石-優先隊列 (355) [48/109]

Problem F: 瑞瑞的木板-優先隊列 (1691) [40/107]

Tips

這三個題是一毛一樣的,代碼也是通用的
B 和 D 就不用說了,樣例都是一樣的
這個 F 是要把大木板切成小木板,反過來就是把小木板合成大木板
注意要定義成小頂堆,不要默認的大頂堆 <(^-^)>

Code

三題通用代碼 ,嘿嘿 ~

#include <bits/stdc++.h>
using namespace std;

int main()
{
	priority_queue<long long,vector<long long>,greater<long long> >q;
	long long tmp,n,sum;
	while(cin>>n)
	{
		sum=0;
		while(!q.empty())q.pop();
		while(n--)
		{
			cin>>tmp;
			q.push(tmp);
		}
		while(q.size()!=1)
		{
			tmp=q.top();
			q.pop();
			tmp+=q.top();
			q.pop();
			sum+=tmp;
			q.push(tmp);
		}
		cout<<sum<<endl;
	}
	return 0;
}

Problem A: 買飯-優先隊列 (1537) [54/114]

Tips

買飯這個看着就眼熟,我記得這個東西叫接水來着
果然 Input 就暴露了它的真實身份,嗯 ~ o( ̄▽ ̄)o

第2行分別表示每人的接水時間

似乎不用優先隊列,貪心方法手動排序一下就行了。

Code

#include <bits/stdc++.h>
using namespace std;

struct People
{
	int t;
	int n;
}p[1001];

int cmp(People p1,People p2)
{
	if(p1.t!=p2.t)return p1.t<p2.t;
	return p1.n<p2.n;
}

int main()
{
	int n;
	double sum=0;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>p[i].t;
		p[i].n=i+1;
	}
	sort(p,p+n,cmp);
	for(int i=0;i<n-1;i++)
	{
		cout<<p[i].n<<" ";
		sum+=(n-i-1)*p[i].t;
	}
	cout<<p[n-1].n<<endl;
	printf("%.2f",sum/n);
	return 0;
}

Problem C: 序列合併-優先隊列 (1689) [23/61]

Tips

這個有點複雜,不過有大佬 jwMM 講解
簡單分析一下,用樣例舉例(非代碼,不可運行)

a[] = 2 6 6
b[] = 1 4 8

用 a 中第 i 個分別加上 b 中元素,得到以下結果

3 6  8
7 10 14
7 10 14

由於給定數據是升序的,因此 同一行左側數據一定大於等於右側數據
3 ≥ 6 ≥ 87 ≥ 10 ≥ 14
那麼只需要先將第一列入優先隊列,然後依次向後查找
每次取最小元素輸出並將最小元素右側元素加入隊列

Code

#include <bits/stdc++.h>
using namespace std;

struct point
{
	int x,y;
	long long sum;
}p;

long long a[400000],b[400000];
bool operator < (const point &p1,const point &p2)
{
	return p1.sum>p2.sum;
}

int main()
{
	priority_queue<point>q;
	int n,ans=0;
	scanf("%d",&n);
	for(int i=0;i<n;i++)scanf("%lld",&a[i]);
	for(int i=0;i<n;i++)scanf("%lld",&b[i]);
	for(int i=0;i<n;i++)
	{
		p.x=0;
		p.y=i;
		p.sum=a[0]+b[i];
		q.push(p);
	}
	while(!q.empty())
	{
		p=q.top();
		q.pop();
		printf("%lld\n",p.sum);
		if(++ans==n)break;
		p.x++;
		p.sum=a[p.x]+b[p.y];
		q.push(p);
	}
	return 0;
}

Problem E: 堆-優先隊列 (1692) [45/55]

Tips

簡單的模板 (shui) 題,練習隊列的基本使用方法。

Code

#include <bits/stdc++.h>
using namespace std;

int main()
{
	priority_queue<long long,vector<long long>,greater<long long> >q;
	long long tmp,n,sum;
	while(cin>>n)
	{
		while(n--)
		{
			cin>>tmp;
			switch(tmp)
			{
				case 1:
					cin>>tmp;
					q.push(tmp);
					break;
				case 2:
					cout<<q.top()<<endl;
					break;
				case 3:
					q.pop();
			}
		}
	}
	return 0;
}

Problem G: 桐桐的新聞系統-優先隊列 (1690) [27/36]

Tips

可以分別記錄每個人的 qnum ,消息的 period 和下次收消息的時間
每次根據時間判斷接收消息的人並輸出序號,同時對應消息回隊列中等待

Code

#include <bits/stdc++.h>
using namespace std;

struct People
{
	int qnum;
	int period;
	long long time;
}p;

bool operator < (const People &p1,const People &p2)
{
	if(p1.time!=p2.time)return p1.time>p2.time;
	return p1.qnum>p2.qnum;
}

int main()
{
	priority_queue<People>q;
	string cmd;
	int n;
	while(cin>>cmd)
	{
		if(cmd=="#")break;
		cin>>p.qnum>>p.period;
		p.time=p.period;
		q.push(p);
	}
	cin>>n;
	while(n--)
	{
		p=q.top(); 
		cout<<p.qnum<<endl;
		p.time+=p.period;
		q.pop();
		q.push(p);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章