逝者如斯,不舍昼夜

尘世中一个迷途小书童,读书太少,想得太多
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

POJ-2726-Holiday Hotel

Posted on 2016-04-03 10:21  SteveWang  阅读(683)  评论(0编辑  收藏  举报

 

                                       Holiday Hotel
 
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 8302   Accepted: 3249

Description

Mr. and Mrs. Smith are going to the seaside for their holiday. Before they start off, they need to choose a hotel. They got a list of hotels from the Internet, and want to choose some candidate hotels which are cheap and close to the seashore. A candidate hotel M meets two requirements: 
  1. Any hotel which is closer to the seashore than M will be more expensive than M. 
  2. Any hotel which is cheaper than M will be farther away from the seashore than M.

 

Input

There are several test cases. The first line of each test case is an integer N (1 <= N <= 10000), which is the number of hotels. Each of the following N lines describes a hotel, containing two integers D and C (1 <= D, C <= 10000). D means the distance from the hotel to the seashore, and C means the cost of staying in the hotel. You can assume that there are no two hotels with the same D and C. A test case with N = 0 ends the input, and should not be processed.
 

Output

For each test case, you should output one line containing an integer, which is the number of all the candidate hotels.
 

Sample Input

5
300 100
100 300
400 200
200 400
100 500
0

 

Sample Output

2

 

-------------------------------------------------

  分析:这道题折腾了我一晚上也没AC,直到第二天早上起来才恍然大悟,心里暗骂出题人100遍,网上有人说貌似是楼教主出的,好吧我承认一开始我对题的理解有问题。首先,这道题的模型很简单,即任何比M旅店离海边近的旅店都比M酒店要贵,至于第二个条件,其实就是第一个条件的逆否命题,用来迷惑你的,嘿嘿!现在的关键是我们如何理解这个条件并把它转化为数学语言,你可能二话不说直接写出了这个数学形式的逻辑语句:∀i,if Di<DM ⇒ Ci>CM ,能写出来这个,证明你高一数学学的很好,跟我一样好。但是我们都犯了一个错误,那就是没有结合题意去讨论特殊情形。首先,我们看一下样例输入,发现有两个旅店距离海边都为100,它们同是离海边最近的旅店,但是它们的价格是不一样的,Smith夫妇选旅店会把它们两个同时作为候选项吗?显然不会!距离相同时,它们当然只会把更便宜的作为候选项,贵的那个直接抛弃!而对于我们之前写的表达式,显然它们两个是都满足的,原因是我们并没有考虑到距离相同时的情形,当然如果出题人好心的话也应该指出这种情况。修改后的逻辑语句:∀i,if Di≤DM ⇒ Ci>CM 

    接下来的思路就明朗了,我们依据离海边的距离对所有旅店进行排序,这里我们使用的是修改后的快速排序(即对D进行排序,C跟随,当然把旅店定义成结构体或类更方便),当两个酒店离海边距离相同时,我们把便宜的那个排在前面,然后我们就可以把D看成自变量x,C看成因变量y,初始时就已经有一个满足条件的旅店M(因为没有比排在最前面的那个旅店离海边更近并且还更便宜的了),即初始时candidate_n = 1,我们从第二个旅店向后扫描C,每找到一个CM比之前的C都小,计数器candidate_n就加1,最后输出candidate_n即可。

  源码

#include<iostream>
using namespace std;

void exchange(int A[], int i, int j)    // 交换A[i]和A[j]
{
    int temp = A[i];
    A[i] = A[j];
    A[j] = temp;
}

int partition(int A[], int B[], int left, int right)// 划分函数
{
    int pivot_A = A[right];                       // 选择子数组最后一个元素作为基准
    int pivot_B = B[right];
    int tail = left - 1;                        // tail为小于基准的子数组最后一个元素的索引
    for (int i = left; i < right; i++)           // 遍历基准以外的其他元素
    {
        if (A[i] < pivot_A)                      // 把小于基准的元素放到前一个子数组中
        {
            tail++;
            exchange(A, tail, i);
            exchange(B, tail, i);
        }
        if (A[i] == pivot_A && B[i] < pivot_B)    // 当两个酒店离海边距离相同时,我们把便宜的那个排在前面
        {
            tail++;
            exchange(A, tail, i);
            exchange(B, tail, i);
        }
    }
    exchange(A, tail + 1, right);               // 最后把基准放到前一个子数组的后边,剩下的子数组既是大于基准的子数组
    exchange(B, tail + 1, right);
    return tail + 1;                           // 返回基准的索引
}

void quicksort(int A[], int B[], int left, int right)
{
    int pivot_index = A[right];
    if (left < right)
    {
        pivot_index = partition(A, B, left, right);
        quicksort(A, B, left, pivot_index - 1);
        quicksort(A, B, pivot_index + 1, right);
    }
}

int main()
{
    int N,candidate_n = 0;
    while (scanf("%d", &N) && N)                // 输入酒店的个数N,N为0时直接结束程序
    {
        int* D = (int *)malloc(N * sizeof(int));// 为了节省空间这里我们根据N的大小动态分配内存
        int* C = (int *)malloc(N * sizeof(int));
        for (int i = 0; i < N; i++)
        {
            scanf("%d%d", &D[i], &C[i]);
        }
        quicksort(D, C, 0, N - 1);              // 调用修改后的快排算法依据D对旅店进行排序,C跟随
        int min = C[0];
        candidate_n = 1;                        // 排在最前面的旅店必然满足条件
        for (int i = 1; i < N; i++)
        {
            if (C[i] < min)                     // 每找到一个旅店比前面的都便宜
            {
                min = C[i];
                candidate_n++;                  // 计数器加1
            }
        }
        printf("%d\n", candidate_n);
        candidate_n = 0;
        free(D);                                // 释放空间
        free(C);
    }
    return 0;
}

 

  显然,程序的时间复杂度O(nlogn),运行结果如下: