我如何设计这个算法?

问题描述

在想象中的土地上,如果人们面对面,他们就有能力互相传送。我应该编写一个算法来找出根据输入进行多少次隐形传送。如果有 1 表示此人面向右侧,如果有 2 则表示此人面向左侧。

第一行是一个数字N,这片土地上的人数。 第二行有N个数字,1或2。

Input         Output
3             2
1 2 2

Input         Output
4             0
2 2 1 1

这是我的代码,但是当一个面朝右的人遇到一个面朝左的人时,他们会相互传送,但算法不会检查是否有更多的人面朝第一个人身后。

int main()
{
    int n,a,teleportiranja = 0;
    cin >> n;
    int niza[n];

    for (int i = 0; i < n; i++)
    {
        cin >> a;
        niza[i] = a;
    }

    for (int x = 0; x < n; x++)
    {
        if (niza[x] == 1 && niza[x + 1] == 2)
        {
            swap(niza[x],niza[x + 1]);
            teleportiranja++;
        }
     }

   cout << teleportiranja << endl;

   return 0;
}

解决方法

您确实检查了第一个人后面的人,但是在检查了所有人一次之后,您就停下来了。您需要第二个循环来不断检查传送,直到找不到其他传送为止。像这样:

#include <iostream>

using namespace std;

int main() {
    int n,a,teleportiranja = 0;
    cin >> n;
    int niza[n];

    for (int i = 0; i < n; i++) {
        cin >> a;
        niza[i] = a;
    }

    bool required_teleports;
    do {
        for (int x = 0; x < n; x++) {
            required_teleports = false;
            if (niza[x] == 1 && niza[x + 1] == 2) {
                swap(niza[x],niza[x + 1]);
                teleportiranja++;
                required_teleports = true;
            }
        }
    } while (required_teleports);
    cout << teleportiranja << endl;

    return 0;
}
,

每个面朝左边的人(值 2)都必须超过他前面的所有面朝右面的人(值 1)。因此,如果我们选择任何值为 2 的人,他将传送的数量等于在他之前的值为 1 的人的数量。这可以通过跟踪 1 的数量在 O(n) 时间内通过单个循环完成far,当我们达到 2 时,我们将当前 1 的数量添加到传送总数中。

int main() {
    int n;
    cin >> n;

    int ones = 0;
    int cnt = 0;
    for (int i = 0; i < n; i++)
    {
        int a;
        cin >> a;
        if (a == 1)
            ones++;
        else cnt += ones;
    }
   cout << cnt << endl;

   return 0;
}