2023年hncpc F 题 宝石交易

186 阅读2分钟

题意

给定两串项链 , 找出使得两串项链相等的最小代价 , 可以自己选择起点

思路

将问题抽象成图论问题,使用Floyd算法求出任意两点之间的最短路。再使用贪心做法,枚举每个起点即可。

其中,存在一步优化。即,在枚举起点时,只需要枚举B串项链的每个点,A串固定1号位置即可。

举例:
A : 1 2 3
B : a b c       这里给出a b  c 只是为了好区分

起点 : 1 a
1 2 3
a b c

起点 : 1 b
1 2 3
b c a

起点 : 1 c
1 2 3           
c a b


就随便拿一个来说: 起点为 1 c
其实它已经枚举完 起点 1 c 、 2 a 、 3 b
那么 枚举3种起点 其实已经枚举完 9 种起点了

本题难度一般,主要是想到如何在正确时间复杂度贪心存在难度

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

#define LL long long
const int N = 400 , INF = INT_MAX;


int n , m;
LL g[N + 1][N + 1];


int main() {

	std::ios::sync_with_stdio(0);
	std::cin.tie(0);
	std::cout.tie(0);

	std::cin >> n >> m;
	std::vector<int> t1(2 * n + 1) , t2(2 * n + 1);

	for (int i = 1; i <= n; i ++ ){
		std::cin >> t1[i];
		t1[i + n] = t1[i];
	}
	for (int i = 1; i <= n; i ++ ) {
		std::cin >> t2[i];
		t2[i + n] = t2[i];
	}

	for (int i = 1; i <= N; i ++ )
		for (int j = 1; j <= N; j ++ )
			if (i != j) g[i][j] = INF;

	while (m -- ){
		LL a , b , c;
		std::cin >> a >> b >> c;
		g[a][b] = std::min(g[a][b] , c);
	}

	for (int k = 1; k <= N; k ++ )
		for (int i = 1; i <= N; i ++ )
			for (int j = 1; j <= N; j ++ )
				g[i][j] = std::min(g[i][j] , g[i][k] + g[k][j]);

	LL ans = INF;
	for (int i = 1; i <= n; i ++ ) {

		LL sum = 0;
		bool ok = 1;
		int l = i , r = i + n - 1;						// 选择 l 作为起点 , r 作为终点
		for (int j = l , k = 1; j <= r; j ++ , k ++ )
			if (t1[k] != t2[j]){
				int u = t1[k] , v = t2[j];

				sum += std::min(g[u][v] , g[v][u]);
				if (sum >= INF) {
					ok = 0;
					break;
				}
			}

		if (ok) ans = std::min(ans , sum);
	}

	std::cout << (ans == INF ? -1 : ans) << '\n';

    return 0;
}