ACM: 最小堆 poj 2274  思路清晰, …

本文探讨了在设定条件下,n辆不同起始位置和速度的赛车比赛中,计算超车事件次数及具体超车时间的过程。通过扫描方法确定各车可被超车次数,并利用最小堆数据结构实现按时间顺序输出首次10000次超车事件。重点分析了超车事件的判断逻辑及最小堆的使用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

The Race
Description
During the Annual Interstellar Competition for Tuned Spaceships, N spaceships will be competing. Each spaceship i is tuned in such a way that it can accelerate in zero time to its maximum speed Vi and remain cruising at that speed. Due to past achievements, each spaceship starts at a starting position Xi, specifying how many kilometers the spaceship is away from the starting line.
The race course is infinitely long. Because of the high speeds of the spaceships, the race course goes straight all the time. On that straight course, spaceships can pass one another very easily, without interfering with each other.
Many people in the audience have not realized yet that the outcome of the race can be determined in advance. It is your task to show this to them, by telling them how many times spaceships will pass one another, and by predicting the first 10 000 times that spaceships pass in chronological order.
You may assume that each spaceship starts at a different position. Furthermore, there will never be more than two spaceships at the same position of the course at any time.
ACM: <wbr>最小堆 <wbr>poj <wbr>2274 <wbr> <wbr>思路清晰, <wbr>实现复杂

Input

The first line of the input specifies the number of spaceshipsN (0 < N <= 250 000) that are competing. Each of the next N lines describe the properties of one spaceship. The i+1th line describes the ith ship with two integers Xi and Vi, representing the starting position and the velocity of the ith spaceship (0 <= Xi <= 1 000 000, 0 < Vi < 100). The spaceships are ordered according to the starting position, i.e. X1 < X2 < . . . < XN. The starting position is the number of kilometers past the starting line where the spaceship starts, and the velocity is given in kilometers per second.

Output

The first line of the output should contain the number of times that spaceships pass one another during the race modulo 1 000 000. By publishing the number of passes only modulo 1 000 000, you can at the same time prove your knowledge of it and don't spoil the party for the less intelligent people in the audience.
Each of the subsequent lines should represent one passing, in chronological order. If there would be more than 10 000 passings, only output the first 10 000 passings. If there are less than 10 000 passings, output all passings. Each line should consist of two integers i and j, specifying that spaceship i passes spaceship j. If multiple passings occur at the same time, they have to be sorted by their position on the course. This means that passings taking place closer to the starting line must be listed first. The time of a passing is the time when the two spaceships are at the same position.

Sample Input

4

0 2
2 1
3 8
6 3

Sample Output

2 
3 4
1 2

题意: 有n辆车, 在不同的位置上面, 每辆车有相应的速度, 现在要你求出超车时间的次数, 和每次超车的
         两部车的编号.

解题思路:
        1. 第一个问题就是逆序数问题, 速度的范围0~100不大, 可以用扫描的方法, 因为题目给出的汽车的,
            顺序的从小编号到大编号, 当前第i 这部车的速度为v , 它可以被超车的数量num[v+1]+...+num[100];
        2. 第二个问题, 我们假设, 对于任何时刻, 一个超车事件的发生, 必定是某辆车被离它最近的车辆超过,
            我们就保存这样的一个时刻, 记录下当前车辆的id, 和要被超车的车辆id, 还有超车的时间需要多少,
            超车之后当前车辆的位置. 此时问题可以解决, 每一个超车事件被我们记录在最小堆里面, 依次取出
            需要时间最短输出即可.
         3. 问题又来了, 当一辆车超过一辆车之后, 一辆车被一辆车超过之后, 会产生新的超车时间, 因为我们只
             保存了两车相离最近的超车事件, 因此我们需要维护这个最小堆.
             问题分析:
                 设4个变量         car_now  //当前车的id
                                          car_front  //当前车的前面那辆车的id
                                          car_back  //当前车的后面那辆车的id
                                          car_front_front //前面那辆车的前面那辆车的id
                  当一个超车事件发生, 这四部车的关系即发生关系, 如图:
ACM: <wbr>最小堆 <wbr>poj <wbr>2274 <wbr> <wbr>思路清晰, <wbr>实现复杂

ACM: <wbr>最小堆 <wbr>poj <wbr>2274 <wbr> <wbr>思路清晰, <wbr>实现复杂
             4. 最后需要注意的是: 输出是有次数要求的, 还有一个是, 可能当前最小的超车事件可能不能用.
                 因为前一个超车时间改变了它.这个需要修正一下即可, 即是: 排除它不输出

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
#define MAX 250005
#define MOD 1000000

struct node
{
    double position, v;
}car[MAX];

struct node_pass
{
    double time, position;
    int id, front;
};

struct cmp
{
    bool operator() (const node_pass &a, const node_pass &b)
    {
        if(a.time > b.time) return true; //时间短的先取
        else if(b.time > a.time) return false;
        else
        //时间相同, 距离小的先取
            if(a.position > b.position) return true;
            else return false;
        }
    }
};

typedef priority_queue< node_pass, vector<node_pass>, cmp > pri_queue;

int n;
int num[105];
int back[MAX], front[MAX];
pri_queue qu;
long long result;

void read_data()
{
    memset(front,-1,sizeof(front));
    memset(back,-1,sizeof(back));
    memset(num,0,sizeof(num));
    result = 0;
   
    for(int i = 0; i < n; ++i)
    {
        scanf("%lf %lf",&car[i].position, &car[i].v);
        num[(int)car[i].v]++;
        for(int j = (int)car[i].v+1; j <= 100; ++j)
            result = (result + num[j]) % MOD;
    }
    //初始化前后车的关系
    front[0] = 1;
    back[n-1] = n-2;
    for(int i = 1; i < n-1; ++i)
    {
        front[i] = i+1;
        back[i] = i-1;
    }
    //将全部超车的事件放入最小堆里面
    node_pass temp;
    for(int i = 0; i < n-1; ++i)
    {
        if(car[i].v > car[i+1].v)
        {
            temp.time = (car[i+1].position-car[i].position) / (car[i].v-car[i+1].v);
            temp.id = i;
            temp.position = car[i].position + temp.time*car[i].v;
            temp.front = i+1;
            qu.push(temp);
        }
    }
}

void solve()
{
    node_pass temp;
    int car_now, car_front, car_back, car_front_front;
    for(int i = 0; i < 10000 && !qu.empty(); ++i)
    {
        temp = qu.top();
        qu.pop();
        car_now = temp.id; //当前车的id
        car_front = temp.front; //当前车的前面那辆车的id
        car_back = back[temp.id]; //当前车的后面那辆车的id
        car_front_front = front[car_front]; //前面那辆车的前面那辆车的id
       
        //修正前后车的关系, 当发现关系变化之后不输出
        if(back[car_front] != car_now || front[car_now] != car_front)
        {
            --i;
            continue;
        }
        printf("%d %d\n",car_now+1, car_front+1);
       
        //调整4部车的前后关系
        if(car_back != -1) front[car_back] = car_front;
        back[car_front] = car_back;
        front[car_front] = car_now;
        front[car_now] = car_front_front;
        back[car_now] = car_front;
        if(car_front_front != -1) back[car_front_front] = car_now;
       
        if(car_back != -1 && car_front != -1)
        {
            if(car[car_back].v > car[car_front].v)
            {
                temp.id = car_back;
                temp.time = (car[car_front].position-car[car_back].position) / (car[car_back].v-car[car_front].v);
                temp.position = car[car_back].position + temp.time*car[car_back].v;
                temp.front = car_front;
                qu.push(temp);
            }
        }
       
        if(car_front_front != -1 && car_now != -1)
        {
            if(car[car_now].v > car[car_front_front].v)
            {
                temp.id = car_now;
                temp.time = (car[car_front_front].position-car[car_now].position) / (car[car_now].v-car[car_front_front].v);
                temp.position = car[car_now].position + temp.time*car[car_now].v;
                temp.front = car_front_front;
                qu.push(temp);
            }
        }
    }
}

int main()
{
//    freopen("input.txt","r",stdin);
    while(scanf("%d",&n) != EOF)
    {
        read_data();
        printf("%lld\n",result);
        solve();
     
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值