繁体   English   中英

有人可以向我解释这种方法吗?

[英]Can someone please explain this approach to me?

我正在通过 USACO 培训网站工作。 我发现这个问题要求我们在三值序列中找到最小的交换次数。 虽然我已经用 O(n^2) 解决方案解决了这个问题,但我很想找出这种更快的 O(n) 方法。 但是,作为初学者,我发现它相当难以理解。


这是详细的问题陈述和最佳方法。

在此任务中,可能的键值是整数 1、2 和 3。所需的排序顺序是非递减的。 但是,排序必须通过一系列交换操作来完成。 由两个 position 编号 p 和 q 定义的交换操作交换位置 p 和 q 中的元素。

您将获得一系列键值。 编写一个程序,计算使序列排序所需的最少交换操作数。

#include <fstream>

using namespace std;

int min (int a, int b) { return a < b ? a : b; }
int max (int a, int b) { return a > b ? a : b; }

int main () {
    int s[1024];
    int n;
    int sc[4] = {0};
    
    ifstream fin("sort3.in");
    ofstream fout("sort3.out");
    fin>>n;
    for (int i = 0; i < n; i++) {
        fin>>s[i];
        sc[s[i]]++;
    }
    int s12 = 0, s13 = 0, s21 = 0, s31 = 0, s23 = 0, s32 = 0;
    for (int i = 0; i < sc[1]; i++){
        if (s[i] == 2) s12++;
        if (s[i] == 3) s13++;
    }
    
    for (int i = sc[1]; i < sc[1]+sc[2]; i++){
        if (s[i] == 1) s21++;
        if (s[i] == 3) s23++;
    }
    
    for (int i = sc[1]+sc[2]; i < sc[1]+sc[2]+sc[3]; i++){
        if (s[i] == 1) s31++;
        if (s[i] == 2) s32++;
    }
    
    fout<<min(s12, s21)+min(s13, s31)+min(s23, s32) +
                    2*(max(s12, s21) - min(s12, s21))<<endl;
    return 0;
}

我得到了我们在各自所需范围 [0->c1, c1->c1+c2, c1+c2->n] 中取最小重叠的部分。 但是,我不太明白 2*max(s12, s21) - min(s12, s21) 的公式。 还有为什么我们不在公式中考虑 s13、s31、s23 和 s32。 我希望您向我解释这一点,因为我不打算在我的训练中留下任何未弥补的空白。 提前致谢!

如果我们从另一个角度处理问题并在示例中计算出如何执行交换,我们可以看到交换次数的公式来自何处。

如果我们开始:

22121 23331 1231
  • s123
  • s130
  • s211
  • s233
  • s312
  • s321

然后用1交换( min(s12, s21) )交换12给出:

12121 23332 1231

13之间没有交换( min(s13, s31) )。

然后用1交换( min(s23, s32) )交换23给出:

12121 22332 1331

现在我们没有更多的直接交换了,我们需要交换两次才能将剩余的元素放到正确的位置。 错位有 2 个1 ,错位有2个,错位有 2 个3 ,每个数字的数字必须始终相同。 错位的1的初始数量由max(s12, s21)给出,我们已经修复了那些留下max(s12, s21) - min(s12, s21) min(s12, s21)待修复。 我们需要执行 2 次交换来修复每个不正确的元素。

首先将1 s 应该在的2 s 与3 s 应该在的1 s 交换,这需要2交换,给出:

11111 22332 2332

现在我们可以直接交换2 s 和3 s,再进行2交换,得到最终结果:

11111 22222 3333

将掉期总数相加得出:

min(s12, s21) + min(s13, s31) + min(s23, s32) + 2*(max(s12, s21) - min(s12, s21))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM