[BZOJ1697][Usaco2007 Feb]Cow Sorting牛排序
1697: [Usaco2007 Feb]Cow Sorting牛排序
Time Limit: 5 Sec Memory Limit: 64 MB Submit: 712 Solved: 416 [Submit][Status][Discuss]Description
农夫JOHN准备把他的 N(1 <= N <= 10,000)头牛排队以便于行动。因为脾气大的牛有可能会捣乱,JOHN想把牛按脾气的大小排序。每一头牛的脾气都是一个在1到100,000之间的整数并且没有两头牛的脾气值相同。在排序过程中,JOHN 可以交换任意两头牛的位置。因为脾气大的牛不好移动,JOHN需要X+Y秒来交换脾气值为X和Y的两头牛。 请帮JOHN计算把所有牛排好序的最短时间。
Input
第1行: 一个数, N。
第2~N+1行: 每行一个数,第i+1行是第i头牛的脾气值。
Output
第1行: 一个数,把所有牛排好序的最短时间。
Sample Input
3
2
3
1
输入解释:
队列里有三头牛,脾气分别为 2,3, 1。
2
3
1
输入解释:
队列里有三头牛,脾气分别为 2,3, 1。
Sample Output
7
输出解释:
2 3 1 : 初始序列
2 1 3 : 交换脾气为3和1的牛(时间=1+3=4).
1 2 3 : 交换脾气为1和2的牛(时间=2+1=3).
输出解释:
2 3 1 : 初始序列
2 1 3 : 交换脾气为3和1的牛(时间=1+3=4).
1 2 3 : 交换脾气为1和2的牛(时间=2+1=3).
排个序找出每头牛应该排到的位置,然后可以发现交换的牛一定是属于同一个置换循环里,那么对于每个循环单独考虑
有两种方法搞
第一是每个元素和最小的一直换
第二种是把外面的最小的换进来再不停换,最后换回来
两种取个最小值就行了
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; char buf[10000000], *ptr = buf - 1; inline int readint(){ int n = 0; char ch = *++ptr; while(ch < '0' || ch > '9') ch = *++ptr; while(ch <= '9' && ch >= '0'){ n = (n << 1) + (n << 3) + ch - '0'; ch = *++ptr; } return n; } typedef long long ll; const int maxn = 10000 + 10; int num[maxn], pos[maxn], a[maxn]; bool vis[maxn] = {false}; int main(){ fread(buf, sizeof(char), sizeof(buf), stdin); int N = readint(); for(int i = 1; i <= N; i++) num[i] = a[i] = readint(); sort(a + 1, a + N + 1); for(int i = 1; i <= N; i++) pos[i] = lower_bound(a + 1, a + N + 1, num[i]) - a; ll ans = 0; for(int j, Min, tot, siz, i = 1; i <= N; i++){ if(vis[i]) continue; Min = tot = num[i]; siz = 1; vis[i] = true; j = pos[i]; while(!vis[j]){ Min = min(Min, num[j]); tot += num[j]; siz++; vis[j] = true; j = pos[j]; } ans += min((ll)Min * (siz - 2), (ll)a[1] * (siz + 1) + Min) + tot; } printf("%lld\n", ans); return 0; }