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 和下次收消息的时间
每次根据时间判断接收消息的人并输出序号,同时对应消息回队列中等待

扫描二维码关注公众号,回复: 9238797 查看本文章

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;
}
发布了62 篇原创文章 · 获赞 202 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/csg999/article/details/104291914