洛谷P1583
三、
魔法照片 点击打开链接
1、双优先队列
#include<bits/stdc++.h>
using namespace std;
priority_queue<pair<int,int> > q;
priority_queue<pair<int,int> > q1;//自创算法:双优先队列。。。
int a[11];//保存额外权值
int main()
{
int n,k;
cin>>n>>k;
for(int i=1;i<=10;i++)
cin>>a[i];//读入额外权值
for(int i=1;i<=n;i++)
{
int h;
cin>>h;
q.push(make_pair(h,i*-1));//优先队列插入,i*-1是因为序号小的优先。
}
for(int i=0;i<n;i++)
{
int h=q.top().first;//记录原始值
int v=q.top().second;//记录原始序号。
q.pop();//弹
h+=a[i%10+1];//根据题意,更新h值。
q1.push(make_pair(h,v));//将h和v踢进第二个优先队列。
}
for(int i=0;i<k-1;i++)
{
cout<<q1.top().second*-1<<' ';//输出不细说。
q1.pop();
}
cout<<q1.top().second*-1<<endl;
return 0;
}
2、结构体+两次快速排序
#include<cstdio>
#include<algorithm>
using namespace std;
struct Person{
int id,w;
}p[10000001]; //结构体,方便些
int n,k,E[11];
bool cmp(Person,Person); //排序的函数
int main(){
scanf("%d%d",&n,&k); //输入
for(int i=1;i<=10;i++) scanf("%d",&E[i]);
for(int i=0;i<n;i++){
scanf("%d",&p[i].w);
p[i].id=i+1;
}
sort(p,p+n,cmp); //sort函数,需带algorithm头文件
for(int i=0;i<n;i++)
p[i].w+=E[i%10+1];
sort(p,p+n,cmp);
for(int i=0;i<k;i++) printf("%d ",p[i].id); //输出
return 0;
}
bool cmp(Person a,Person b){
if(a.w==b.w) return a.id<b.id;
return a.w>b.w;
}
3、
题目实际上指的是先给定你1~n号对应的权值,从大到小排序后根据当前次序再编第二次号,分类别加上对应的e[i],再次从大到小进行排序后输出前k大权值分别的初始编号。
注意!第二次编号与最终的编号输出无关,仅用于分类。
举个例子:
输入:(测试点#1)
14 3 9 2 5 4 0 0 0 0 0 0
1 1 3 4 9 2 8 2 8 8 8 7 1 9
编号为:1 2 3 4 5 6 7 8 9 10 11 12 13 14
第一次排序后:(序号小优先)
9 9 8 8 8 8 7 4 3 2 2 1 1 1
编号为:5 14 7 9 10 11 12 4 3 6 8 1 2 13
类别为:1 2 3 4 5 6 7 8 9 10 1 2 3 4
加上e[i]后:18 11 13 12 8 8 7 4 3 2 11 3 6 5
第二次排序后:(序号小优先)
18 13 12 11 11 8 8 7 6 5 4 3 3 2
编号为:5 7 9 8 14 10 11 12 2 13 4 1 3
输出:5 7 9
这就是这道题大概的思路:输入——排号——排序——分类加e[i]——排序——输出
如果对上面的推导过程有什么疑问,可以自己动手尝试。
最后附上代码,希望能帮到大家(`・ω・´):
#include<cstdio>
#include<algorithm>
using namespace std;
int e[12],n,k;
struct person{
int w;//权值
int num;//编号
int d;//类别
}p[20010];//储存每个人的信息
int w_comp(const person &a,const person &b){
if(a.w!=b.w)return a.w>b.w;//从大到小排序
return a.num<b.num;//序号小优先
}//结构体排序
int main(){
scanf("%d%d",&n,&k);
for(int i=0;i<10;i++)scanf("%d",&e[i]);
for(int i=0;i<n;i++){
scanf("%d",&p[i].w);
p[i].num=i+1;
}//读入+编号
sort(p,p+n,w_comp);//第一次排序
for(int i=0;i<n;i++){
p[i].d=i%10;//分类
p[i].w+=e[p[i].d];//加上e[i]
}
sort(p,p+n,w_comp);//第二次排序
for(int i=0;i<k;i++)printf("%d ",p[i].num);
}
二、
P1051 谁拿了最多奖学金
https://www.luogu.org/problemnew/show/P1051#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;
struct node{
string xm;//姓名
int qm,bj;//期末平均成绩,班级评议成绩
char bgb,xb;//是否是学生干部,是否是西部省份学生
int lw;//发表的论文数
int ans;//个人所获的奖金数
int sum;//序号数,因为题目要求两个人所获的奖金数相同时,输出先出现的,即序号较靠前的(较小的)
}a[101];
int n,tot=0;
bool cmp(node x,node y)
{
if(x.ans==y.ans)return x.sum<y.sum;
else return x.ans>y.ans;//奖学金数从大到小排序,相同时按序号数从小到大排序
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
cin>>a[i].xm>>a[i].qm>>a[i].bj>>a[i].bgb>>a[i].xb>>a[i].lw;
if(a[i].qm>80&&a[i].lw>=1)a[i].ans+=8000;
if(a[i].qm>85&&a[i].bj>80)a[i].ans+=4000;
if(a[i].qm>90)a[i].ans+=2000;
if(a[i].xb=='Y'&&a[i].qm>85)a[i].ans+=1000;
if(a[i].bj>80&&a[i].bgb=='Y')a[i].ans+=850;
a[i].sum=i;
tot+=a[i].ans;//tot为总的奖学金数
}
sort(a+1,a+n+1,cmp);
cout<<a[1].xm<<endl<<a[1].ans<<endl<<tot;
return 0;
}
结构体和快排
三、
P1093 奖学金
https://www.luogu.org/problemnew/show/P1093
sort
#include<cstdio>
#include<algorithm>
using namespace std;
int n;
struct student{
int c,m,e,tot,num;//定义
}s[301];
int student_comp(const student &a,const student &b){//两个结构体
if(a.tot>b.tot)return 1;
if(a.tot<b.tot)return 0;//总分比较
if(a.c>b.c)return 1;
if(a.c<b.c)return 0;//语文比较
if(a.num<b.num)return 1;//序号比较
return 0;
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d%d%d",&s[i].c,&s[i].m,&s[i].e);//语数英读入
s[i].tot=s[i].c+s[i].m+s[i].e;//总分计算
s[i].num=i+1;//序号
}//读入
sort(s+0,s+n,student_comp);//排序
for(int i=0;i<5;i++)printf("%d %d\n",s[i].num,s[i].tot);//输出
}