[Usaco2007 Feb]Cow Sorting牛排序

 农夫JOHN准备把他的 N(1 <= N <= 10,000)头牛排队以便于行动。因为脾气大 的牛有可能会捣乱,JOHN想把牛按脾气的大小排序。每一头牛的脾气都是一个 在1到100,000之间的整数并且没有两头牛的脾气值相同。在排序过程中,JOHN 可以交换任意两头牛的位置。因为脾气大的牛不好移动,JOHN需要X+Y秒来交 换脾气值为X和Y的两头牛。 请帮JOHN计算把所有牛排好序的最短时间。


这题刚开始我还以为是逆序对。

后来想了想。

需要求个置换,然后每个置换内部搞就可以了。 这时每个元素必然不在自己的位置上。

然后置换内部搞的话。

首先肯定是拿最小的元素跟其他元素换来换去。

这样在内部肯定是最优的。

但是我没考虑到一个问题就是, 我既然可以拿置换内部最小的去跟别的元素换。  我也可以所有数中最小的元素换到这个置换中,再去跟置换内部的其他元素换来换去,换完之后,再把之前的数换回来就行了。

那么就有这两种方案取最优就行了。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define MAXN 111111
#define MAXM 211111
#define PI acos(-1.0)
#define eps 1e-8
#define INF 100000001
using namespace std;
int a[MAXN], b[MAXN], c[MAXN];
int n;
vectorg[MAXN];
int vis[MAXN];
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        b[i] = a[i];
    }
    sort(b + 1, b + n + 1);
    for(int i = 1; i <= n; i++) c[b[i]] = i;
    int cnt = 0;
    for(int i = 1; i <= n; i++)
    {
        int id = c[a[i]];
        if(vis[id]) continue;
        cnt++;
        vis[id] = cnt;
        int nxt = c[a[id]];
        while(nxt != id)
        {
            vis[nxt] = cnt;
            nxt = c[a[nxt]];
        }
    }
    for(int i = 1; i <= n; i++)
    {
        int id = c[a[i]];
        g[vis[id]].push_back(a[i]);
    }
    long long sum = 0;
    for(int i = 1; i <= cnt; i++)
    {
        int sz = g[i].size();
        int mi = INF;
        for(int j = 0; j < sz; j++) sum += g[i][j], mi = min(mi, g[i][j]);
        sum -= mi;
        sum += min((sz - 1) * mi, (sz - 1) * b[1] + 2 * (b[1] + mi));
    }
    printf("%lld\n", sum);
    return 0;
}



你可能感兴趣的:(BZOJ)