列表

详情


NC220558. 挪酒瓶

描述

你有  瓶酒,第  瓶重量为 w_i,想要交换到位置 a_i

每次可以选择两个酒瓶,交换他们的位置,花费为两个酒瓶的重量和。

求把所有酒瓶交换到指定位置最小的花费

输入描述

第一行一个正整数 ,代表测试数据的组数

每组测试数据有3行,第一行一个正整数 ,表示酒瓶的数量

第二行  个正整数 a_i,表示第  个酒瓶想要到  位置上。输入保证  到  在  中恰出现一次。

第三行个正整数,表示第瓶酒的重量为

输出描述

每组输入数据输出一行,代表花费

示例1

输入:

2
4
2 1 4 3
10 20 30 40
3
2 3 1
10 20 30

输出:

100
70

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

Python3(3.9) 解法, 执行用时: 1765ms, 内存消耗: 31856K, 提交时间: 2021-04-23 13:29:30

T = int(input())
while T:
    T -= 1
    ans = 0    
    N = int(input())
    p = list(map(int,input().split(' ')))
    for i in range(N):
        p[i] -= 1
    w = list(map(int,input().split(' ')))
    allmin = min(w)
    vis = [0] * N
    for i in range(N):
        if vis[i] == 0:
            j = i
            cnt = 0
            sumnow = 0
            nowMin = float('inf')
            while vis[j] == 0:
                vis[j] = 1
                cnt += 1
                sumnow += w[j]
                nowMin = min(nowMin,w[j])
                j = p[j]
            ans += min(sumnow + (cnt - 2) * nowMin, sumnow + nowMin + (cnt + 1) * allmin)
    print(ans)            

C++(clang++11) 解法, 执行用时: 208ms, 内存消耗: 1072K, 提交时间: 2021-04-10 19:47:45

#include <stdio.h>
#include <algorithm>
#include <vector>
#define MN 100000

int n,a[MN+5],w[MN+5];

void solve(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)
		scanf("%d",&w[i]);
	int ans = 0;
	int minw = 233;
	for(int i=1;i<=n;i++)
		minw = std::min(minw,w[i]);
	for(int i=1;i<=n;i++){
		if(!w[i]) continue;
		int p = i;
		int tot = 0;
		int lminw = 233;
		int cnt = 0;
		do{
			tot += w[p];
			lminw = std::min(lminw,w[p]);
			w[p] = 0;
			cnt++;
			p = a[p];
		}while(p!=i);
		ans += std::min((cnt-2)*lminw+tot,minw*(cnt+1)+tot+lminw);
	}
	printf("%d\n",ans);
}

int main(){
	int T; scanf("%d",&T);
	while(T--) solve();
}

上一题