【PAT A1046】/ 【Code Up E】 Shorest Distance(20)

简单模拟 介绍

PAT甲乙级中入门模拟题,入门模拟题又分为简单模拟,查找元素
图形输出,日期处理,进制转换,字符串处理等等!

何为模拟题?

模拟题是一类“题目怎么说,你就怎么做的”的题目
如果实现不太麻烦可以称之为就“简单模拟”!!!

此类题目不涉及算法,完全根据题目描述进行代码的编写

主要考察代码能力

虽听起来可能蛮简单的,但绝不是1 + 1 = 2的题目!!!

有些题实现起来确实有小难度!

本次讲述两道稍微拔高的模拟题

PAT 甲级 A1046 Shortest Distance (20分)
问题 E: Shortest Distance (20)

两题来自不同的平台但是题目是一某一样且code up 在本题上更为严谨一些!!!

题目描述

The task is really simple: given N exits on a highway which forms a simple cycle
you are supposed to tell the shortest distance between any pair of exits.

输入

Each input file contains one test case. For each case, the first line contains 
an integer N (in [3, 105]), followed by N integer distances D1 D2 ... DN, where 
Di is the distance between the i-th and the (i+1)-st exits, and DN is between 
the N-th and the 1st exits. All the numbers in a line are separated by a space.
The second line gives a positive integer M (<=104), with M lines follow, each 
contains a pair of exit numbers, provided that the exits are numbered from 
1 to N. It is guaranteed that the total round trip distance is no more than 107.

输出

For each test case, print your results in M lines, each contains the shortest
distance between the corresponding given pair of exits.

样例输入 Copy

5 1 2 4 14 9
3
1 3
2 5
4 1

样例输出 Copy

3
10
7

题意
高速公路上有n个出口,分为为1 ~ n个,第一行输入d1 d2.。。。。。dn
d1表示1出口到2出口的距离, 。。。。。。。dn表示n出口到1出口的距离,大体知道是一个环

输入第一行表示各个出口之间的距离。接着输入3个测试用例,每个测试用例输入两个出口,最后输出每个测试用例中两个出口之间最短的距离。

#include <iostream>
using namespace std;
int s[100000];
int main()
{
    int N, M;
    cin >> N;
    int temp;
    int sum = 0;
    for (int i = 1; i <= N; i++)//为了更清楚我选择从1开始存储,更加清晰明了
    {
        cin >> temp;
        s[i] = temp;
    }
    cin >> M;
    int a, b;
    for (int j = 0; j < M; j++) {
        int sum1 = 0, sum2 = 0;
        cin >> a >> b;
        if (a == b) cout << 0 << endl;
        if (a > b) {//例如 5 2 ,我先计算 2 ~5 之间的距离,再计算 5 ~ 2的距离
        
         for (int k = b; k < a; k++)
                sum1 += s[k];
                
         for (int k = a; ;) {
                sum1 += s[k];
                k++;
                if (k > N) k = 1;
                if (k == b) break;
            	}
       	}
         if ( a < b ) {
            for (int k = a; k < b; k++)
                sum1 += s[k];
            for (int k = b; ;) {
                sum2 += s[k];
                k++;
                if (k > N) k = 1;
                if (k == a) break;
            }
        }
        cout << (sum1 > sum2 ? sum2 : sum1) << endl;//然后输出最小值
    }
    return 0;
    
   }//其实代码逻辑完全符合题意,且编译通过!最后oj给出的答案是超时!!!

既然超时,我们想如何使时间更加缩短呢?, 苦思冥想

  1. 发现这是一个循环.我们可以计算一边的距离,接着用总距离减一边的距离等于另一边的距离。
  2. 接着又发现在 ·1 ·~ 5中,如果测试用例输入的是 1 2,那么肯定先计算 1 ->2边的距离后用总距离将其相减得 2 -> 1边的距离。
  3. 但是如果输入的是1 4呢? 那么肯定先计算 4 -> 1边的距离并用总距离将其相减得1 -> 4的距离
  4. 总之计算短一边的距离

想到此时立马激动起来去实现代码并提交

#include <iostream>
using namespace std;
int s[100000];
int main()
{
    int N, M;
    cin >> N;
    int temp;
    int sum = 0;
    for (int i = 1; i <= N; i++)
    {
        cin >> temp;
        s[i] = temp;
        sum += temp;//sum来的到总环距离
    }
    cin >> M;
    int a, b;
    for (int j = 0; j < M; j++) {
        int sum1 = 0, sum2 = 0;
        cin >> a >> b;
        if (a == b) cout << 0 << endl;
        if (a > b) {
            int t = a;
            a = b;
            b = t;
        }
        if ((b - a) <= (N/2))//判断计算哪边的距离更少
        {
            for (int k = a; k < b; k++)
                sum1 += s[k];
        }
        else
        {
            for (int k = b; ;) {
                sum1 += s[k];
                k++;
                if (k > N) k = 1;
                if (k == a) break;
            }
        }
        sum2 = sum - sum1;

        cout << (sum1 > sum2 ? sum2 : sum1) << endl;//最后输出最短距离
    }
    return 0;
   }

但事与愿违 oj反馈的结果依旧是超时!!!

我彻底崩溃啦!我实在想不到该如何优化啦?
(注明:该代码在PAT里提交未显示超时,在Code Up显示超时.可能不同oj不一样吧,但在该题上Code up蛮严谨的)
未加载请刷新
未加载请刷新
我今天继续来看这道题,发现题目提供的数据范围还是蛮大的nteger N (in [3, 10^5]), integer M (<=104)如果数据这么大,如果N 为 10^5次方,然后输入的测试用例是 1 (10^5 )/2 两个出口,虽然上面那个代码只需计算最短的一个方向,但是也是太大啦!!!

题目要求限制在1000ms内那是不可能的,怎样继续优化?可否使时间复杂度为O(1)呢?

可以的

设置一个dis数组来记录从1位置到i为位置的距离,用dis[i]表示
最后两出口的距离只需用dis[right-1] - dis[left-1]来计算,具体操作看C++代码!
最终AC掉啦!!!(code up)

#include <iostream>
using namespace std;
const int MAX = 100005;
int s[MAX];
int dis[MAX];
int main()
{
    int N, M;
    cin >> N;
    int temp;
    int sum = 0;
    dis[0] = 0;//这里使dis[0],left==1的情况会使用
    for (int i = 1; i <= N; i++)
    {
        cin >> temp;
        sum += temp;
        dis[i] = sum;//记录从1位置到  i 位置的距离
    }
    cin >> M;
    int left, right;
    for (int j = 0; j < M; j++) {
        cin >> left >> right;
        if (left == right) cout << 0 << endl;
        if (left > right) {//始终保持left<right
            int t = left;
            left = right;
            right = t;
        }
        int sum1 = dis[right - 1] - dis[left - 1];
        //两段的距离直接相减即可,大大降低时间复杂度
        int sum2 = sum - sum1;
        cout << (sum1 > sum2 ? sum2 : sum1) << endl;
    }
    return 0;
}


©️2020 CSDN 皮肤主题: 岁月 设计师:pinMode 返回首页