【问题标题】:SPOJ: GENERAL (Time limit exceeded)SPOJ:一般(超过时间限制)
【发布时间】:2016-10-29 18:35:14
【问题描述】:

我已经尝试在 spoj 上解决这个简单的问题 (http://br.spoj.com/problems/GENERAL/) 已经有一段时间了,但由于某种原因,我不断收到 TLE(超出时间限制)。

由于问题是葡萄牙语,问题的简要描述是这样的(没有故事):

给定一个大小为 N 的数组,你必须将数组排列在 升序,这样一个元素只能交换 距离它 k 的元素。如果数组可以 sorted 然后打印排列它们所需的交换次数 升序,如果不能排序打印 impossivel.

这是我的代码::

#include <iostream>
#include <cstdio>

using namespace std;
int a[100005];
int main() {
    int t;
    int n, k;
    scanf("%d", &t); //number of test cases
    while(t--) {
        scanf("%d %d", &n, &k);
        bool result = true;
        int count = 0;

        for(int i = 0; i < n; i++) {
            scanf("%d", &a[i]);
        }

        for(int i = n; i > 0; i = i - k) {
            int j = 0;
            for( ; j < i - k; j++) {
                if(a[j] > a[j + k]) {
                    int temp = a[j];
                    a[j] = a[j + k];
                    a[j + k] = temp;
                    count++;
                }
            }

            for( ; j < i - 1; j++) {
                if(a[j] > a[j + 1]) {
                    result = false;
                    break;
                }
            }

            if(!result)
                break;
        }
        if(result)
            printf("%d\n", count);
        else
            printf("impossivel\n");
    }
}

我的逻辑:我对数组执行 N/k 次迭代。我将循环变量 i 初始化为 N。在每次迭代中,我检查 ik 元素与距离它 k 的元素,如果要交换它们,那么我交换它们并增加所需的交换次数,否则我什么都不做。然后我检查从 iki 的元素,如果它们按升序排列,如果不是,我打破循环并打印“impossivel”,否则我更改 i ik 并再次执行循环。根据我的逻辑,每次迭代后最后的 k 元素将按升序排列,如果可以对它们进行排序,因为在每一步我都会将较大的元素向右移动。

这对您来说是否正确?如何进一步优化呢?感谢您提前提供任何帮助。 :)

【问题讨论】:

  • 你可能会在Code Review上得到更好的回复
  • 您使用了冒泡排序算法,就时间复杂度而言,这是最糟糕的算法之一。
  • 您可以使用诸如gprof 之类的分析工具来确定瓶颈的实际位置。
  • 另外,是否有必要显示要求输入的代码和 while 循环这样做?为什么不先写代码的“肉”,你知道,真正解决问题的部分,在某种你可以测试的函数中?我在这些 SPOJ 帖子中一遍又一遍地看到这一点——所有输入例程添加的内容都很混乱。
  • @PaulMcKenzie:根据要求,OP 不能使用其他排序。

标签: c++ arrays algorithm sorting


【解决方案1】:

分成 k 个子列表,每个子列表有 n/k 个元素。

检查不可能条件。

不可能的条件

设 k = 2,

3 4 1 2 是数组

对于 n/k 个列表,维护数组以查看一个数字是否存在于 O(1) 中。

例如。间隔为 2

我们可以分成两个子列表,3 1 和 4 2 现在我们知道 sorted 是

1 2 3 4(使用计数排序作为 1 和 n 之间的高度 O(n))

所以,我们期望 1 排在第一位。现在问,1可以来吗?如果只是它在子列表中。[Y]

如果 [N] 说“不可能”

如果不可能,我们就完成,否则继续。

k次归并排序,k * n/k(log(n/k))

(反转次数等于对数组排序的最小相邻交换次数[已知属性] 参考: Sorting a sequence by swapping adjacent elements using minimum swaps )

方法的复杂度是 n log n ,很容易通过:)

【讨论】:

  • 我在将数组分解为更小的列表时考虑了相同的一般想法,但没有进一步解决细节。 OP 使用冒泡排序的答案绝对不是解决这个问题的方法。
  • 对于{5, 2, 3, 4, 1},交换区为4,res 为1,而不是反转数。
  • @Jarod42 分成列表。首先间隙为 4 :5,1 然后 2 ,然后 3 然后 4。[接下来的间隙为 4 不可用] 反转次数的总和是 1+0+0+0,这就是答案。如果现在清楚,请告诉我:)
  • @Ishan 谢谢 :) 帮助很大。
猜你喜欢
  • 2016-04-07
  • 1970-01-01
  • 2015-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-18
相关资源
最近更新 更多