POJ 3270 Cow Sorting 置换群

Cow Sorting

接触到置换群的概念,对于一个(1~n)的一个排列a1, a2, a3...an

    1   2   3   4   5 ... n

   a1  a2 a3 a4 a5...an

看作是一个置换,那么将其写为若干个不相交的循环的乘积形式(A1, A2, ... Ap1)(B1, B2, ... Bp2)... ...,例如

   1 2 3 4 5 6

   3 5 6 4 2 1

可以写为(1 3 6)(2 5)(4)的形式,这里可以看成有3个循环(可以理解为上面的1 3 6这个集合,对应在下面也是 1 3 6)

 

那么对应在每一个循环中,可以通过最多Ki - 1此交换使得这个循环有序,这里的Ki表示第i个循环的集合的大小。也就是说每交换一次可以使得一个元素回到自己的位置,由于交换的代价是这两个元素值的和,那么根据贪心的思想,每次选择用这个循环中的最小值将其他元素交换到对应的位置上去。那么总代价就是

SUMi + (Ki - 2) * Mi

这里Mi表示第i个循环的最小值,SUMi表示第i个循环的和,Ki表示这个循环的元素的个数。

 

另外,从另一个角度出发,如果整个序列的最小值非常小,那么我们判断是不是可以先用整个序列的最小值把第i个循环的最小值Mi换出来,然后将这个集合(循环)交换到有序后,再将Mi交换回来,这样总代价就是

SUMi + (Ki + 1) * MIN + Mi

其中MIN表示整个序列的最小值。

 

那么,最后的答案就是  ans = SIGMA{ SUMi + min{(Ki - 2) * Mi,  (Ki + 1) * MIN + Mi} }

 

 1 #pragma comment(linker, "/STACK:1677721600")
 2 #include <map>
 3 #include <set>
 4 #include <stack>
 5 #include <queue>
 6 #include <cmath>
 7 #include <ctime>
 8 #include <bitset>
 9 #include <vector>
10 #include <cstdio>
11 #include <cctype>
12 #include <cstdarg>
13 #include <cstring>
14 #include <cstdlib>
15 #include <iostream>
16 #include <algorithm>
17 using namespace std;
18 #define INF 0x3f3f3f3f
19 #define inf (-((LL)1<<40))
20 #define root 1, 1, n
21 #define middle ((L + R) >> 1)
22 #define lson k<<1, L, (L + R)>>1
23 #define rson k<<1|1,  ((L + R)>>1) + 1, R
24 #define mem0(a) memset(a,0,sizeof(a))
25 #define mem1(a) memset(a,-1,sizeof(a))
26 #define mem(a, b) memset(a, b, sizeof(a))
27 #define FIN freopen("in.txt", "r", stdin)
28 #define FOUT freopen("out.txt", "w", stdout)
29 #define rep(i, a, b) for(int i = a; i <= b; i ++)
30 #define dec(i, a, b) for(int i = a; i >= b; i --)
31 
32 //typedef __int64 LL;
33 typedef long long LL;
34 typedef pair<int, int> Pair;
35 const int MAXN = 300000 + 10;
36 const int MAXM = 1100000;
37 const double eps = 1e-12;
38 LL MOD = 1000000007;
39 
40 int n;
41 struct Node {
42     int a, id;
43     bool operator < (const Node &A) const {
44         return a < A.a;
45     }
46 }node[MAXN];
47 bool vis[MAXN];
48 
49 int find_ans(int p, int &mi, int &cnt) {
50     int sum = 0;
51     mi = INF;
52     cnt = 0;
53     do {
54         sum += node[p].a;
55         vis[p] = 1;
56         cnt ++;
57         mi = min(mi, node[p].a);
58         p = node[p].id;
59     } while(!vis[p]);
60     return sum;
61 }
62 
63 int main()
64 {
65 #ifndef ONLINE_JUDGE
66     FIN;// FOUT;
67 #endif
68     while(~scanf("%d", &n)) {
69         int mi = INF;
70         rep (i, 1, n) {
71             scanf("%d", &node[i].a);
72             node[i].id = i;
73             mi = min(mi, node[i].a);
74         }
75         sort(node + 1, node + n + 1);
76         mem0(vis);
77         int cur_min, cur_cnt, ans = 0;
78         rep (i, 1, n) if(!vis[i]) {
79             int sum = find_ans(i, cur_min, cur_cnt); // 找到当前循环的元素个数,最小值
80             if(cur_cnt > 1) {// mi表示所有数字中的最小值
81                 ans += sum + min( (cur_cnt - 2) * cur_min, (cur_cnt + 1) * mi + cur_min );
82             }
83         }
84         cout << ans << endl;
85     }
86     return 0;
87 }

 

转载于:https://www.cnblogs.com/gj-Acit/p/4713330.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值