poj 3270 Cow Sorting 【置换群】【求 把一个序列变成升序 所需代价】

Cow Sorting
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 6364   Accepted: 2462

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).
 
 
题意不多说了。
 
分析:通过这n个数组成的数列 我们可以得到若干个置换子群。
            比如 给定序列{
                                            3  1  7  10  6
                                            1  3  6   7  10
                                        }上面序列要变成下面序列。 我们可以得到2个置换子群(3 -> 1 -> 3)(7 -> 6 -> 10 -> 7)。
接下来有两种方法变换序列:
 
(1)  在子群里面置换 -> 用最小的元素sonMin和其它 t - 1 元素交换 t - 1 次,就有花费1:sum + (t - 2) * sonMin;
(2)  借助于外界元素置换 -> 先让数列中最小元素Minn和群中最小元素sonMin交换,再用Minn与其它 t - 1个元素交换 t - 1 次,然后把Minn和sonMin交换回来
       有花费2: sum + sonMin + Minn * (t + 1)。
提醒: sum为当前群的数值之和。因此可以先统计所有元素之和,然后每次加上min(花费1, 花费2)即可;
 
对于每个置换群的求法,我用的是结构体存储原数值以及原数值对应的位置,然后按数值升序排列就求出变换的位置。
 
序列{                                                                                   {
              数值 3  1  7  10  6         ------>                                    数值 1  3  6  7 10
              位置 1  2  3   4   5         ------>                                    位置   2  1  5  3  4
          }                                                                                   }
 
 
代码实现:
 
#include 
#include 
#include 
#define LL long long
#define MAX 10000+10
#define INF 1000000000+10
using namespace std;
struct record
{
	int val, pos;//分别表示 数值和这个数有哪个位置的数置换得到的 
}num[MAX]; 
bool cmp(record a, record b)
{
	return a.val < b.val;//按照数值升序排列 
}
int a[MAX];//n个数 
int vis[MAX];//标记当前元素在不在某一个子群里面 
int main()
{
	int n, i, j;
	LL ans;//最小 花费 
	int Minn;//记录数列里面最小值 
	int sonMin;//记录当前子群的最小值 
	int t;//记录子群元素个数 
	while(scanf("%d", &n) != EOF)
	{
		Minn = INF; ans = 0;
		for(i = 1; i <= n; i++) 
		{
			scanf("%d", &a[i]);
			ans += a[i]; 
			num[i].val = a[i];
			num[i].pos = i;
			Minn = min(Minn, a[i]);//记录数列里面最小的值 
		}
		sort(num+1, num+n+1, cmp);//升序排列 
		memset(vis, 0, sizeof(vis));//初始化 
		for(i = 1; i <= n; i++)
		{
			j = i;
		    if(!vis[j])//不存于 当前所有置换子群中 
			{
				t = 0;
				sonMin = a[j];
				while(!vis[j])
				{
					vis[j] = 1;//标记 
					t++;//元素个数加一 
					sonMin = min(sonMin, a[j]);//更新子群最小值 
					j = num[j].pos;//->变换到它的上一位置 
				}
				ans += min((t-2)*sonMin, (t+1)*Minn+sonMin);
			}
		} 
		printf("%lld\n", ans);
	}
	return 0;
}

你可能感兴趣的:(置换群poyla)