5

我们有列表 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有点陌生,但如果我不明白这一点,我就不会睡觉

4

1 回答 1

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_)
于 2021-02-23T20:55:46.490 回答