862-AlvinZH的儿时梦想——运动员篇

思路

难题。

应该想到,不管给出的数据如何,每一个淘汰的人不会对最终答案产生任何影响,所以每次淘汰就把人除掉就可以了,最后剩下的两个人计算它们从开始到相遇需要的时间就可以了。

首先对每个人根据初始位置进行排序,因为相遇总是先发生在相邻的两个人身上的,所以一开始先对相邻的人两两计算相遇时间,然后把相遇时间放进优先队列里(保证时间短的优先出队),然后依次出队,判定见面的两个人中哪个会被淘汰,然后把淘汰的人除去,维护新建立起来的相邻关系,以及新的相遇时间放进优先队列,一直处理直到队列只剩最后一对,然后取出来计算时间就可以了。

需要使用循环链表记录每一个人的相邻位置是谁,简单使用两个数组即可模拟循环链表。

本题还要注意的是环形跑道,也就是说在计算时间的时候记得相应处理,比如对跑道长度取模。注意看下列的求时间函数:

double getTime(int rear, int front)
{
int dx = (P[front].pos - P[rear].pos + L) % L;//相对距离
int dv = P[rear].v - P[front].v;//相对速度
if (dv < 0)//front追rear
{
dv = -dv;
dx = L - dx;
}
return (dx * 1.0 / dv);
}

分析

考察的是优先队列和循环链表。

最初状态环上有n个人,每次淘汰的必然是环上相邻的选手。注意到第一个被淘汰的人不会对后续过程有任何影响,所以找到这个人并把他从状态环上删去,就能把问题变成一个只有n-1人的子问题,此子问题与原问题有相同的答案。

利用优先队列维护状态环上所有相邻的人相遇的时间,每次取出最小值,可以淘汰一人,注意淘汰一人后,原本不相邻的人就相邻了,需要求得新的相遇时间入队,重复这一过程,直到队列剩余元素为1时结束。

考察了大家的模拟能力和手速,代码挺长,想起来还是挺简单的,对吧?

参考代码

//
// Created by AlvinZH on 2017/9/25.
// Copyright (c) AlvinZH. All rights reserved.
// #include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <functional>
#include <algorithm>
#define MaxSize 100005
using namespace std; struct Person {
int pos,v,power;
bool operator < (const Person& x) const {
return pos < x.pos;//按位置从小到大排序,pos小的优先级大(sort函数)
}
}; struct Race {
int front,rear;//两个人对应下标
double time;//相遇时间
Race(int r = 0,int f = 0,double t = 0.0) {
rear = r;front = f;time = t;
} bool operator < (const Race& r) const {
return time > r.time;//相遇时间小的位于队首(优先队列)
}
}; int n,L;
Person P[MaxSize];
int nextP[MaxSize],lastP[MaxSize];//记录下一个和上一个人的标号
bool isOUT[MaxSize];//记录是否被淘汰
priority_queue<Race> Q;//优先队列 double getTime(int rear, int front)
{
int dx = (P[front].pos - P[rear].pos + L) % L;//相对距离
int dv = P[rear].v - P[front].v;//相对速度
if (dv < 0)//front追rear
{
dv = -dv;
dx = L - dx;
}
return (dx * 1.0 / dv);
} int main()
{
//freopen("in1.txt", "r", stdin);
//freopen("out2.txt", "w", stdout);
int T;
scanf("%d", &T);
while (T--)
{
scanf("%d %d", &n, &L); for (int i = 0; i < n; i++) {
scanf("%d %d %d", &P[i].pos, &P[i].v, &P[i].power);
}
sort(P, P + n); while (!Q.empty()) Q.pop(); for (int i = 0; i < n; i++) {
double t = getTime(i, (i + 1) % n);
Q.push(Race(i,(i+1)%n,t)); lastP[i] = (i - 1 + n) % n;
nextP[i] = (i + 1) % n;
} int All = n;//剩余比赛人数
memset(isOUT, false, sizeof(isOUT)); while (Q.size() > 1)
{
Race tmp = Q.top();
Q.pop();
int rear = tmp.rear,front = tmp.front;
if(isOUT[rear] || isOUT[front])
continue;
if(lastP[rear] == front && nextP[front] == rear)//剩余最后两人
break; if(P[rear].power > P[front].power)//rear追上front,淘汰front
{
isOUT[front] = true;
nextP[rear] = nextP[front];
lastP[nextP[front]] = rear;
double tt = getTime(rear, nextP[front]);
Q.push(Race(rear, nextP[rear], tt));
}
else
{
isOUT[rear] = true;
lastP[front] = lastP[rear];
nextP[lastP[rear]] = front;
double tt = getTime(lastP[front], front);
Q.push(Race(lastP[front], front, tt));
} if(--All <= 0)
break;
} Race tmp = Q.top();
Q.pop();
printf("%.3lf\n", tmp.time);
}
} /*
* 考点:优先队列
* 坑:数据量较大
*/

2016级算法第二次上机-E.AlvinZH的儿时梦想——运动员篇的更多相关文章

  1. 2016级算法第二次上机-C.AlvinZH的儿时梦想——坦克篇

    872 AlvinZH的儿时梦想----坦克篇 思路 简单题.仔细看题,题目意在找到直线穿过的矩形数最小,不能从两边穿过.那么我们只要知道每一行矩形之间的空隙位置就可以了. 如果这里用二维数组记住每一 ...

  2. 2016级算法第二次上机-A.画个圈圈诅咒你

    890 画个圈圈诅咒你 思路 简单题.题目中的圆并没有什么实际作用,简化成线段重合问题会更好理解些. 暴力解法:使用双重for循环会T到想哭,记住最直接的方法一般是过不了题的. 解法一:二分查找.空间 ...

  3. 2016级算法第二次上机-G.ModricWang's Real QuickSort

    873 思路 这是一道非常基础的题,目的是帮助大家回顾快排相关的知识.大家完成此题之后应该就对快排有比较深刻的印象了. 对于整个快排的流程,题目描述中已经给了清晰完整的伪代码.需要自己加工的部分就是, ...

  4. 2016级算法第二次上机-F.ModricWang's Number Theory II

    891 ModricWang's Number Theory II 思路 使得序列的最大公约数不为1,就是大于等于2,就是找到一个大于等于2的数,它能够整除序列中的所有数. 考虑使得一个数d整除数组中 ...

  5. 2016级算法第二次上机-D.Bamboo的饼干

    Bamboo的饼干 分析 从两个数组中各取一个数,使两者相加等于给定值.要注意去重和排序 难度不大,方法很多,基本只要不大于O(n^2 ) 的都可以过.本意想考察二分搜索 还可以借助stl中的map, ...

  6. 2016级算法第二次上机-B.Bamboo的OS实验

    Bamboo的OS实验 分析 首先理解题意,要完成不同数量的不同命令,但是完成相同的命令之间必须有n个间隔,为使得时间最短,自然优先用其他命令来填充这n分钟的时间,由于数量少的命令可以用来填充空隙,所 ...

  7. 2016级算法第一次练习赛-F.AlvinZH的儿时梦想——机器人篇

    864 AlvinZH的儿时梦想----机器人篇 题目链接:https://buaacoding.cn/problem/868/index 思路 中等题. 判断无限玩耍: \(p\) 的值能够承担的起 ...

  8. 2016级算法期末模拟练习赛-F.AlvinZH的青春记忆IV

    1086 AlvinZH的青春记忆IV 思路 难题,动态规划. 这是一道很有意思的题,因为它不仅卡了时间,也卡了空间,而且卡的很妙很迷. 光是理解题意已经有点难度,简化题意:两串数字序列,相等的数字定 ...

  9. 2016级算法期末模拟练习赛-C.AlvinZH的青春记忆II

    1084 AlvinZH的青春记忆II 思路 中等题,二分. 简化题意,一列数字,每秒会自动-1,特殊操作可以使一个数在1s内-k,问这些数都减至0需要多久. 答案肯定在[1,xMax]之间,采用二分 ...

随机推荐

  1. Opencv 计算图片旋转角度

    vector<vector<Point>> vec_point;vector<Vec4i> hireachy;findContours(img_canny1, ve ...

  2. XIb中使用tableview报错UIViewAlertForUnsatisfiableConstraints

    1.使用断点工具并不能找出错误,最后仔细看了下报错信息 2.报错信息 [LayoutConstraints] Unable to simultaneously satisfy constraints. ...

  3. 257. Binary Tree Paths返回所有深度优先的遍历

    [抄题]: Given a binary tree, return all root-to-leaf paths. For example, given the following binary tr ...

  4. scp 的时候提示WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!

    摘自:https://blog.csdn.net/haokele/article/details/72824847   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ...

  5. wsl命令行

    参考: https://docs.microsoft.com/en-us/windows/wsl/about 查看已安装 wslconfig /l /all 重装 wslconfig /u debia ...

  6. 【转】C语言中DEFINE简介及多行宏定义

    要写好C语言,漂亮的宏定义是非常重要的.宏定义可以帮助我们防止出错,提高代码的可移植性和可读性等. 在软件开发过程中,经常有一些常用或者通用的功能或者代码段,这些功能既可以写成函数,也可以封装成为宏定 ...

  7. JavaEE互联网轻量级框架整合开发(书籍)阅读笔记(8):装配SpringBean概述(如何合理使用装配级别)

    一. 装配Bean概述  关于如何将自己开发的Bean配置到Spring IoC容器中,大部分场景下,我们都会使用ApplicationContext的具体实现类,因为对应的Spring IoC容器功 ...

  8. 编写高质量代码改善C#程序的157个建议——建议89:在并行方法体中谨慎使用锁

    建议89:在并行方法体中谨慎使用锁 除了建议88所提到的场合,要谨慎使用并行的情况还包括:某些本身就需要同步运行的场合,或者需要较长时间锁定共享资源的场合. 在对整型数据进行同步操作时,可以使用静态类 ...

  9. iOS设计模式之单例

    单例模式的意思就是这个类只有一个实例,这个类就是单例类.在iOS中有不少都是单例NSNull,NSFileManager ,UIApplication,NSUserDefaults ,UIDevice ...

  10. Delphi XE8 iOS与Android移动应用开发(APP开发)教程[完整中文版]

    https://item.taobao.com/item.htm?id=536584650957&toSite=main