【问题标题】:Perform best cycle sort knowing order at the end最后执行最佳循环排序知道顺序
【发布时间】:2021-05-26 00:25:03
【问题描述】:

我们有列表 A,排序后需要看起来像列表 B,我们有每个数字的努力或“权重”,所以当我们按顺序交换时,努力也会交换,它们是连接的。

知道列表最后应该是什么样子找到将列表 A 排序为看起来像 lis B 所需的最低努力

我找到了我的问题的答案,但它在 C++ 代码中位于底部

6 <--- how many numbers there is
w = [2400, 2000, 1200, 2400, 1600, 4000] <----- effort 
a = [1, 4, 5, 3, 6, 2] <----- starting list
b = [5, 3, 2, 4, 6, 1] <----- how it should be sorted

所以当我们移动时

2 和 5 我们取第二个和第五个权重并将它们相加,所以 努力是 3600,列表看起来像这样

a = [1, 4, 2, 3, 6, 5]

sum_effort = 3600

然后我们移动 3 和 4 这个移动的努力又是 3600 并且看起来像这样

a = [1, 3, 2, 4, 6, 5]

sum_effort = 7200

然后是 1 和 5,所以 这个动作的努力是 4000 并且列表看起来像 b 列表

sum_effort 为 11200

我基于 c++ 做了什么

weight = [2400, 2000, 1200, 2400, 1600, 4000]
og = [1, 4, 5, 3, 6, 2]
position = [5, 3, 2,4, 6, 1]

result = 0
for x in range(len(og)):
    suma    = 0
    min_cycle = 0
    len_cycle = 0
    current  = x

    while(1):
    
        min_cycle = min(min_cycle, weight[current])
        
        suma = suma + weight[current]
        current = position[current]
            
        len_cycle += 1
        if current == x:
            break
        
    result += min(suma+(len_cycle-2)*min_cycle, suma+min_cycle+(len_cycle+1)*min_weight)
print(result)

#include <cstdio>
#include <algorithm>

#define REP(a,n) for (int a=0; a<(n); ++a)

using namespace std;

#define INF 1000000000

typedef long long LL;

///////////////////////////

#define MAXN 1000000

int wagi[MAXN];
int orig[MAXN]; // orgin
int perm[MAXN]; // end_pos
bool vis[MAXN]; 

int minw = INF; // minimalna waga

int main()
{
    int N;
    scanf("%d", &N);
    REP(a, N)
    {
        scanf("%d", &wagi[a]);
        minw = min(minw, wagi[a]);
    }
    REP(a, N)
    {
        scanf("%d", &orig[a]);
        --orig[a];
    }
    REP(a, N)
    {
        int nr;
        scanf("%d", &nr);
        --nr;
        perm[nr] = orig[a];
    }
    LL wynik = 0;
    REP(pocz, N)
        if (!vis[pocz])
        {
            int minc = INF; 
            LL suma = 0; 
            int cur = pocz;
            int dl = 0; 
            for (;;) 
            {
                minc = min(minc, wagi[cur]);
                suma += wagi[cur];
                cur = perm[cur];
                vis[cur] = true;
                ++dl;
                if (cur==pocz)
                    break;
            }
            wynik += min(suma+(dl-2)*(LL)minc, suma+minc+(dl+1)*(LL)minw);
        }
    printf("%Ld\n", wynik);
}

我对 python 有点陌生,但如果我不明白这一点,我不会去睡觉

【问题讨论】:

  • 可能执行cycle sort
  • 这些努力是否与交换书籍一起交换?或者这是在这个特定地点拿/放一本书的“惩罚”?
  • 他们互换了

标签: python c++ algorithm sorting cycle-sort


【解决方案1】:

我决定坐下来尝试解决这个问题。如果我理解正确,我们正在列表上执行交换,以便让它们像在目标列表中一样排序。

我们可以执行两种类型的操作。将两个数字交换到目的地,这是交换两个数字,它们都落在它们所属的地方。并将一个号码交换到目的地,这会使其中一个落在它所属的位置,而将另一个放在不正确的位置。

完美交换应始终优先于单个元素到目标。把它写在纸上后,我还得出结论,当做一个元素到目标交换时,为了最小化总和,你移动最小元素的次数越多,总和就越小。

所以,我想出的算法是:在目标中找到最小的权重元素,找到应该在它的位置,切换它们。然后从目标列表和原始列表中删除所有位于正确位置的元素(如果前一个已经在目标列表中,则可以找到新的最小权重),循环直到列表为空。

程序将使用一对一的交换来移动最小的权重,当它完成时,选择下一个最小的元素。当程序选择其中一个元素作为最小权重时,双向完美交换将自行解决。

我不确定这个算法是否完全正确,尤其是在极端情况下,但这是我能想出的最好的算法,我的时间很少。

def remove_correct_places(org,trg,orgw):
    indexes_to_delete = []

    for index, tpl in enumerate(zip(org, trg)):
        if tpl[0] == tpl[1]:
            indexes_to_delete.append(index)

    for index in reversed(indexes_to_delete):
        org.pop(index)
        trg.pop(index)
        orgw.pop(index)

weight = [2400, 2000, 1200, 2400, 1600, 4000]
origin = [1, 4, 5, 3, 6, 2]
target = [5, 3, 2, 4, 6, 1]


weights = {nr+1:item for nr, item in enumerate(weight)}
# list of weights in order corresponding to origin
origin_weights= [weights[x] for x in origin]
sum_ = 0

#ignoring elements that are in their places already
remove_correct_places(origin,target,origin_weights)

# as long as origin isn't empty
while origin_weights:
    # find smallest weight
    min_weight = min(origin_weights)
    # find its index
    min_weight_index = origin_weights.index(min_weight)
    # find which element it corresponds to
    min_weight_element = origin[min_weight_index]

    # find what value should be in that index
    other_element = target[min_weight_index]
    # find index of this value in origin
    other_index = origin.index(other_element)
    # find its weight
    other_weight = weights[other_element]

    # swap the two (both on origin_weight and origin lists) and increase the cumulative sum
    origin[min_weight_index] = other_element
    origin_weights[min_weight_index] = other_weight

    origin[other_index] = min_weight_element
    origin_weights[other_index] = min_weight

    sum_ += other_weight + min_weight

    # removing elements that are on the correct place from the list,
    # because we don't need them anymore
    remove_correct_places(origin, target, origin_weights)

print(sum_)

【讨论】:

  • 这与实际情况非常接近,但正如你所说,我在极端情况下有一些错误,所以我会尝试自己解决问题,如果没有完美的结果会接受答案
  • 既然你这么说,我刚刚意识到当初始列表在正确位置上有一些元素并且其中一个是最小重量时可能会出现问题。列表可能应该在循环之前清除那些正确的位置。它可能会解决极端情况问题。
  • 我更新了答案中的代码以包含该修复。
  • 我已经编辑了我的帖子,也许它会清除一些东西
猜你喜欢
  • 1970-01-01
  • 2022-10-02
  • 1970-01-01
  • 1970-01-01
  • 2021-08-09
  • 2011-04-20
  • 2012-07-15
  • 1970-01-01
  • 2014-05-29
相关资源
最近更新 更多