poj3270


Language: Default
Cow Sorting
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 6834   Accepted: 2675

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

Line 1: A single integer:  N
Lines 2.. N+1: Each line contains a single integer: line  i+1 describes the grumpiness of cow  i

Output

Line 1: A single line with the minimal time required to reorder the cows in increasing order of grumpiness.

Sample Input

3
2
3
1

Sample Output

7

Hint

2 3 1 : Initial order. 
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

USACO 2007 February Gold


这个题很多题解都是标题就是大写的置换群,甚至有的连置换群的各种学术性分析都加进来了,其实这题根本不需要知道置换群是什么,因为用不到置换群的性质,而只需要一个规律,这个规律叫置换群,规律是可以自己观察发现的,而置换群这个名字在这个题里面丝毫没有用。

抽象出模型题意就是:一堆不重复的整数(1~100000),排序为递增序列(从左到右从小到大),可以交换任意两个数不必要相邻,但交换的代价就是两数的和,问最小代价。

我做的时候先把数排列成都不在自己位置上的序列,这样你看从最小的开始交换,占用了谁的最终位置就跟谁换,这样换到最后最小值也就在自己的位置上了,比最小值大的指都加了一次,最小值加了其它数值个数的次数,比如 :

3 1 2   

3 2 1

1 2 3

1交换了2次,2、3各加一次。就是答案7。

那就是要首先找到互相占用别的数值位子的一组数

3 1 2 5 4

1 2 3 4 5

1 2 3就是这样一组数,有一个不在自己最终位置上,其它的数就必然存在一个不在自己位置上。

4 5也是这样一组数,只是比较简单,更加符合上述性质。

这种性质集合就叫置换群,而你不需要知道置换群还有什么性质,那没有帮助。

这样来看一个置换群的最小代价就是:大于最小值的数的和 + 最小值×(序列中数个数 - 1)

开始这样提交的就wrong answer了。

再想想,每个置换群的策略应该是没错的,不在位置上的一定是要交换的,否则达不到目的,而作为媒介

的数自然越小越好,在置换群里面已经是对的了。

而考虑到越小越好,一个置换群里面的最小值自然不比全部数最小值小。

那到底会不会有影响,需要在加之前做个比较。

而多做出的操作就是:

    置换群最小值与实际最小值交换,用实际最小值做媒介,把当前置换群的数值

替换到自己最终的位置上,再用最小值与当前置换群最小值做交换。但这个过程中,比当前置换群中大于最小值的

数加的次数是没有变化的,只需要比较上面的操作值就可以了。

#include 
#include 
#include 
const int N = 100010;
using namespace std;

int rec[10010];
int hash[N];
bool inrec[N];
int main()
{
  
    int n;
    while (~scanf("%d", &n))
    {
      memset(inrec, 0, sizeof(inrec));
      for (int i = 0; i < n; i++)
      {
        scanf("%d", rec + i);
        hash[rec[i]] = i;         //hash数组用于记录排序前每个数的位置
      }
      sort(rec, rec + n);
      int ans = 0;
      for (int i = 0; i < n; i++)
      {
        if (i == hash[rec[i]])    //初始位置与最终位置一样不必交换
          continue;
        if (inrec[rec[i]])        //以及在某个置换群中的数也不做处理
          continue;
        int cur = i;
        int cnt = 0;
       
        while (!inrec[rec[cur]])
        {
          inrec[rec[cur]] = 1;
          cur = hash[rec[cur]];
          cnt++;                 //统计置换群长度
          if (!inrec[rec[cur]])  //保证别加进来最小值,最小值还不一定用当前置换群最小值
            ans += rec[cur];
        }
        ans += min(rec[i] * (cnt - 1), (rec[0] + rec[i])*2 + rec[0] * (cnt - 1));
       }
      printf("%d\n", ans);
    }

    return 0;
}








你可能感兴趣的:(acm)