BZOJ_1697_[Usaco2007 Feb]Cow Sorting牛排序_贪心
BZOJ_1697_[Usaco2007 Feb]Cow Sorting牛排序_贪心
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).
可以发现每头牛都有一个应该去的位置,假设把每个牛向应该去的位置连边,会出现许多个环,每个环里的牛分别自身交换。
交换的方式有两种:1.每个环里最小的那头牛让环里的其他牛都和他交换一次。2.可能整个序列中的最小值比环里最小的要小很多,
那我们先让他俩交换,再用序列中的最小值和环里其他的牛交换一次,然后再交换回来。
处理出每个环里牛的个数,权值和,最小权值。统计即可。
代码:
#include <stdio.h> #include <string.h> #include <algorithm> #include <stdlib.h> using namespace std; #define N 10050 typedef long long ll; ll ans; int siz[N],sol[100050],sum[N],n,a[N],b[N],pos[100050],real_pos[100050],scc,mn[N]; void get_pre() { int i,j; for(i=1;i<=n;i++) { j=i; if(sol[b[j]]) continue; sol[b[j]]=1; ++scc; sum[scc]=mn[scc]=b[j]; siz[scc]=1; while(1) { j=pos[b[j]]; if(sol[b[j]]) break; siz[scc]++; sum[scc]+=b[j]; mn[scc]=min(mn[scc],b[j]); sol[b[j]]=1; } } } int main() { scanf("%d",&n); int i; for(i=1;i<=n;i++) { scanf("%d",&a[i]); b[i]=a[i]; real_pos[a[i]]=i; } sort(a+1,a+n+1); for(i=1;i<=n;i++) pos[a[i]]=i; get_pre(); for(i=1;i<=scc;i++) { if(siz[i]==1) continue; ll tmp=min(1ll*(siz[i]-2)*mn[i],1ll*(siz[i]+1)*a[1]+mn[i])+sum[i]; ans+=tmp; } printf("%lld\n",ans); }