POJ 3270 置换群问题

题目大意是:

每头牛都有一个对应的值a[i],现在给定一个初始的牛的序列,希望通过两两交换,能够使这些牛按值升序排列,每次交换都会耗费一个 a[i]+a[j]

希望耗费最小,求出这个最小耗费

个人觉得这道题还是蛮有意思的,虽然我wa了很多发,但还是很值得思考一下的

这是一个置换群问题,但是我们首先要根据其值排个序确定每头牛本来应该属于的位置,再根据现在所在的位置得到一个映射关系to[i]

将a[i]又用b[]数组保存,排序后,b[i]表示第i大的牛的值

我们找出这个置换群中的所有循环集,每个循环集分别讨论,我们总是找到循环集中值最小的牛占据了别的牛的位置pos,然后把这个pos这个位置交换给对应的牛

这样得到的是b[min]+b[pos],因为每头牛总要回到自己的位置上,假定循环集中有len个牛,那么所有牛都回到自己的位置上那么所有的b[i]都要加一遍

但加的过程希望尽可能的小,所以总是跟b[min]相加,这个是可以保证的,因为在一个循环集中,每次交换最多只能令一个数回到正确位置上,除非到了最后一步

,否则的话,如果同时回到了正确位置,那么这两个数可以独立出来作为一个循环集,这与它们在原来的循环集中是矛盾的

其实到了这里感觉总的思路已经是对的

但是自己就是在这里wa了

想了半天发现还有更优的情况

另外还有一种情况需要考虑就是这个循环集中位置的交换可以利用b[1](也就是最小的牛)来帮忙

是不是通过利用最小编号的牛帮助这个循环集排好队是不是结果更小
最小的牛加进来帮忙就是值为b[1]的牛和当前循环集内最小的牛交换一次位置,帮好忙后再交换回来

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6 const int N = 10005;
 7 const int M = 100005;
 8 int a[N] , b[N] , to[N] , vis[N] , id[M];//to[]记录置换群上的映射关系
 9
10 int circle(int u)
11 {
12     int v = u , ans = 0;
13     int cnt = 0;
14     while(u != to[v]){
15         vis[v] = 1;
16         cnt++;
17         ans = ans+b[v];
18         v = to[v];
19     }
20     ans = ans+b[v] , cnt++;
21     vis[v] = 1;
22     if(cnt == 1) return 0;
23     else{
24         /*这里要判断一下,是不是通过利用最小编号的牛帮助这个循环集排好队是不是结果更小
25         最小的牛加进来帮忙就是值为b[1]的牛和当前循环集内最小的牛交换一次位置,帮好忙后
26         再交换回来*/
27         int tmp = ans + b[u] + (cnt+1)*b[1];
28         return min(tmp , ans + (cnt-2)*b[u]);
29     }
30 }
31
32 int main()
33 {
34   //  freopen("a.in" , "r" , stdin);
35     int n;
36     while(scanf("%d" , &n) != EOF)
37     {
38         for(int i=1 ; i<=n ; i++)
39         {
40             scanf("%d" , a+i);
41             b[i] = a[i];
42         }
43         sort(b+1 , b+n+1);
44         for(int i=1 ; i<=n ; i++)
45             id[b[i]] = i;
46         for(int i=1 ; i<=n ; i++)
47             to[i] = id[a[i]]; //表示第i个位置被第id[a[i]]大的牛占据了
48         memset(vis , 0 , sizeof(vis));
49         int ans = 0;
50         for(int i=1 ; i<=n ; i++)
51             if(!vis[i]) ans += circle(i);
52
53         printf("%d\n" , ans);
54     }
55     return 0;
56 }
时间: 2024-12-29 23:44:11

POJ 3270 置换群问题的相关文章

poj 3270(置换群+贪心)

Cow Sorting Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 6993   Accepted: 2754 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...

poj 3270 Cow Sorting 置换群 简单题

假设初始状态为 a:2 3 1 5 4 6 则目标状态为 b:1 2 3 4 5 6且下标为初始状态中的3 1 2 4 5 6(a[3],a[1]...) 将置换群写成循环的形式 (2,3,1),(5,4),6就不用移动了. 移动方式2种 1:选循环内最小的数和其他len-1个数交换 2:选整个序列最小的数和循环内最小的数交换,转到1,再换回来. #include<cstdio> #include<queue> #include<algorithm> #include&

poj 3270 Cow Sorting(初涉置换群)

http://poj.org/problem?id=3270 大致题意:给出n个整数,要将它们转化成递增序列,每交换其中两个数的代价是这两个数之和.问排序成功后的最小代价. 该题考察的是置换群知识.在黑书p247上有详细的讲解.总结下置换群,方便复习. 群:给定一个集合G={a,b,c...}和集合G上的二元运算 ·,如果满足封闭性,结合律,存在单位元和逆元,则成集合G在运算'·'之下是一个群. 置换:n个元素1,2,....,n之间的置换可表示为  1     2     3     ...

POJ 3270 Cow Sorting(置换群)

题目链接 题意 : N头牛,每个牛的坏脾气都有一个值,每个值都不相同,把这个值按照从小到大排序,如果两个值交换,那么会花掉这两个值之和的时间,让你花最少的时间将每个值从小到大排好序,求最小的总时间. 思路 : 这个在黑书上有写,就是置换群,248页有写.写的挺详细的.每个状态都可以分为若干个循环的乘积.对于任意循环 i ,设其长度为ki,则至少需要交换ki-1次,即每次让一个元素到达目标位置,而当第ki-1个元素到达目标以后显然第ki个也已经到达目标.第一个方法是让循环中最小的元素t参加所有的交

poj 3270 置换

1 poj 3270 置换的应用 黑书原题P248 2 /** 3 题意: 给定序列, 将其按升序排列, 每次交换的代价是两个数之和, 问代价最小是多少 4 思路:1.对于同一个循环节之内的,肯定是最小的与别的交换代价最小 5 2. 对于整个序列中最小的与其交换 ,也可能最小 6 比较这两个大小,即可得出结论 7 对于情况1:代价为 sum+(len-2)*t //len 为每个循环节的长度, t 为每个循环节中最小的那个数 sum 为循环节中所 有数的和 8 对于情况2: 代价: sum+t+

【POJ 3270】Cow Sorting(置换群排序)

Cow Sorting(置换群排序) Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 6909 Accepted: 2716 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

POJ 1026 置换群的k次幂问题

题目大意: 给定了一组对应关系,经过k次幂后,得到新的对应关系b[i],然后将给定的字符串上的第i位字符放置到b[i]的位置上, 如果字符串长度不足n就用空格补足,这里的是空格,也就是str[i] = ' ',不是str[i]='\0' ,自己这里错了好几回就是找不到问题,看了别人代码才明白 置换群的k次幂问题不清楚,可以看看<<置换群快速幂运算+研究与探讨.pdf>> 这里初始给定的置换群要注意这个群不一定是一个循环集,我们要先统计出它的每一个循环集,然后每一个分别进行操作计算

poj 3270 Cow Sorting

Cow Sorting 题意:有N头牛,每头牛都有不同的暴躁值ai,现在要将所有的牛按照暴躁值从小到大排序,每次交换两个元素(任意交换)时,花费就是两头牛的暴躁值之和:问排序的最小花费为多少? 数据:(1 ≤ N ≤ 10,000) (1 <= ai <= 100,000); 思路:很明显的贪心:(下面讲的循环是置换群里的循环) 策略:我们从没在最终位置且值最小的牛看起,如果每次都是将当前考虑的牛直接与它最终的位置的牛交换,那么这样递推下去,将形成的就是一个循环(一定有牛的最终位置为考虑的起始

poj 3270 更换使用

1.确定初始和目标状态. 明确.目标状态的排序状态. 2.得出置换群,.比如,数字是8 4 5 3 2 7,目标状态是2 3 4 5 7 8.能写为两个循环:(8 2 7)(4 3 5). 3.观察当中一个循环,明显地.要使交换代价最小,应该用循环里面最小的数字2.去与另外的两个数字.7与8交换. 这样交换的代价是: sum - min + (len - 1) * min 化简后为: sum + (len - 2) * min 当中,sum为这个循环全部数字的和,len为长度,min为这个环里面