Farmer John有N头牛(1 ≤ N ≤ 10000),这N头牛各自有一个不同的脾气脾气指数L(1 ≤ L ≤ 100000),这N头牛按脾气指数是无序排列,指数越大的越容易破坏farmer的挤奶器,所以farmer为了保护他的设施,要对这些牛按脾气指数递增的顺序排列,但交换两头牛的代价是这两头牛的脾气指数之和,现在告诉你牛的个数N和N头牛的脾气指数Li,求最小代价
大小为 的数列通过交换变成有序的数列, 分析样例(不妨加上两个数字).
初态 | 2 | 3 | 1 | 5 | 4 |
---|---|---|---|---|---|
终态 | 1 | 2 | 3 | 4 | 5 |
将 与 交换, 到了 位置, 于是将 与 交换, 到了 位置, 交换完成.
发现 三者构成了一个环, 同理 也构成了一个环.
于是得出 初步结论 : 在一个环中的数列, 可以交换 次, 独立到达终态 .
然后计算出每个环花费的最小值, 累加起来得到 .
对于每个环, 都有一种最优的执行方案: 用环中的最小元素依次将每个元素归位, 若无外界干涉, 能取得最小值.
但若有外界干涉, 整个数列中的 最小值 去替代环中的最小值, 可能计算出的答案会更加小.
所以计算一个环中的最小花费有两种途径:
- 利用环内的最小值
- 利用整体的最小值
取两种中较小值, 累加进答案即可.
没什么好说的.
#include<cstdio>
#include<algorithm>
#define reg register
const int maxn = 20005;
const int inf = 0x7f7f7f7f;
int N;
int Ans;
int min_v;
int A[maxn];
int B[maxn];
int C[maxn];
int tmp[maxn];
bool Used[maxn];
void Work(int cnt, int min_vv, int sum){
int s_1 = sum - min_vv + (cnt-1) * min_vv;
int s_2 = sum - min_vv + (cnt-1) * min_v + (min_v + min_vv) * 2;
Ans += std::min(s_1, s_2);
}
int main(){
scanf("%d", &N);
min_v = inf;
for(reg int i = 1; i <= N; i ++){
scanf("%d", &A[i]), B[i] = A[i];
min_v = std::min(min_v, A[i]);
}
std::sort(B+1, B+N+1);
int Len = std::unique(B+1, B+N+1) - B-1;
for(reg int i = 1; i <= N; i ++) C[i] = std::lower_bound(B+1, B+Len+1, A[i]) - B;
for(reg int i = 1; i <= N; i ++)
if(!Used[C[i]]){
int to = C[i], cnt = 0, min_tmp = inf, sum = 0;
while(!Used[to]) Used[to] = 1, sum += B[to], min_tmp = std::min(min_tmp, B[to]), to = C[to], cnt ++;
Work(cnt, min_tmp, sum);
}
printf("%d
", Ans);
return 0;
}