Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 7310 | Accepted: 2875 |
Description
Farmer John's N (1 ≤ N ≤ 10,000) cows are lined up to be milked in the evening. Each cow has a unique "grumpiness" level in the range 1...100,000. Since grumpy cows are more likely to damage FJ's milking equipment, FJ would like to reorder the cows in line so they are lined up in increasing order of grumpiness. During this process, the places of any two cows (not necessarily adjacent) can be interchanged. Since grumpy cows are harder to move, it takes FJ a total of X+Y units of time to exchange two cows whose grumpiness levels are X and Y.
Please help FJ calculate the minimal time required to reorder the cows.
Input
Lines 2.. N+1: Each line contains a single integer: line i+1 describes the grumpiness of cow i.
Output
Sample Input
3 2 3 1
Sample Output
7
Hint
2 1 3 : After interchanging cows with grumpiness 3 and 1 (time=1+3=4).
1 2 3 : After interchanging cows with grumpiness 1 and 2 (time=2+1=3).
Source
题意:
大致题意:Farmer John有N头牛(1 ≤ N ≤ 10000),这N头牛都很各应,各自有一个不同的脾气脾气指数L(1 ≤ L ≤ 100000),这N头牛按脾气指数是无序排列,指数越大的越容易破坏farmer的挤奶器,所以farmer为了保护他的设施,要对这些牛按脾气指数递增的顺序排列,但交换两头牛的代价是这两头牛的脾气指数只和,现在告诉你牛的个数N和N头牛的脾气指数Li,求最小代价。
思路:
首先考虑把原始序列变成几个置换。如
3 4 1 5 2 -> (31)(425)
已知置换间是不相影响的,那么对于每个置换,最少需要(len-1)次即可全部归位(len为置换长度)。那么拿这个置换中最小值min将其余牛归位花费一定是最小,为sum+min*(len-1);
但是这个思路是不完全正确的。如果给出的置换中每个环中的那个极小元素就是置换中的最小元素,那上面的思路肯定正确。但如果最小元素不在这个环里,那存不存在更优的策略?答案是存在的。试试1 8 9 7 6这组数据。将它划分成(8 6 9 7)(1),(没写出下标,直接按权划分的),那么我们把1和6交换,让1加入到前面的环中置换那另外三个大数,最后再把6换出来,发现得到的话费比上面给出的策略更优。也就是说置换的次数最少不一定能得到最优。那除了上面给出的两种策略还有其他的更优策略么?从贪心的角度分析不可能有更优了,所以我们只要对上面的两种策略中选择一个较小的即可。 给出两种方案的计算:
第一种策略:sum1=(L1+Min(L))+(L2+Min(L))+...+(Lm-1+Min(L)) 其中:sum1为总花费,Li为此环中的牛脾气质数,除去那个极小的一共m-1个,Min(L)为脾气最小的牛。
整理一下得到:sum1=sum(L)+(m-2)*Min(L)
第二种策略:sum2=(L1+MIN)+(L2+MIN)+...+(Lm-1+MIN)+2*(Min(L)+MIN) 其中MIN为N头牛中脾气最小的
整理一下得到:sum2=sum(L)+Min(L)+(m+1)*MIN
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 1e4 + 5;
struct node
{
int index, val;
}a[maxn];
int book[maxn];
int cmp(node a, node b)
{
return a.val < b.val;
}
int main()
{
int n;
while(~scanf("%d", &n))
{
memset(book, 0, sizeof(book));
int minx = 1e6 + 5, ans = 0;
for(int i = 1; i <= n; i++)
scanf("%d", &a[i].val), a[i].index = i, minx = min(minx, a[i].val);
sort(a+1, a+1+n, cmp);
for(int i = 1; i <= n; i++) //找循环节并更新
{
if(book[i]) continue;
int index = a[i].index;
int sum = a[i].val;
int tminx = a[i].val;
int cnt = 1;
book[i] = 1;
while(index != i)
{
book[index] = 1;
cnt++;
tminx = min(tminx, a[index].val);
sum += a[index].val;
index = a[index].index;
}
ans += min(tminx*(cnt-1)+sum-tminx, 2*(minx+tminx)+minx*(cnt-1)+sum-tminx); //前者用这里面最小的换,后者用全部元素最小的换掉这个循环里最小的,参与置换,最后再换回来
}
printf("%d\n", ans);
}
return 0;
}