您的位置:首页 > 其它

POJ 3270 Cow Sorting 置换群

2015-08-08 16:03 246 查看
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} }

#pragma comment(linker, "/STACK:1677721600")
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <bitset>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstdarg>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define inf (-((LL)1<<40))
#define root 1, 1, n
#define middle ((L + R) >> 1)
#define lson k<<1, L, (L + R)>>1
#define rson k<<1|1,  ((L + R)>>1) + 1, R
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a, b) memset(a, b, sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define rep(i, a, b) for(int i = a; i <= b; i ++)
#define dec(i, a, b) for(int i = a; i >= b; i --)

//typedef __int64 LL;
typedef long long LL;
typedef pair<int, int> Pair;
const int MAXN = 300000 + 10;
const int MAXM = 1100000;
const double eps = 1e-12;
LL MOD = 1000000007;

int n;
struct Node {
int a, id;
bool operator < (const Node &A) const {
return a < A.a;
}
}node[MAXN];
bool vis[MAXN];

int find_ans(int p, int &mi, int &cnt) {
int sum = 0;
mi = INF;
cnt = 0;
do {
sum += node[p].a;
vis[p] = 1;
cnt ++;
mi = min(mi, node[p].a);
p = node[p].id;
} while(!vis[p]);
return sum;
}

int main()
{
#ifndef ONLINE_JUDGE
FIN;// FOUT;
#endif
while(~scanf("%d", &n)) {
int mi = INF;
rep (i, 1, n) {
scanf("%d", &node[i].a);
node[i].id = i;
mi = min(mi, node[i].a);
}
sort(node + 1, node + n + 1);
mem0(vis);
int cur_min, cur_cnt, ans = 0;
rep (i, 1, n) if(!vis[i]) {
int sum = find_ans(i, cur_min, cur_cnt); // 找到当前循环的元素个数,最小值
if(cur_cnt > 1) {// mi表示所有数字中的最小值
ans += sum + min( (cur_cnt - 2) * cur_min, (cur_cnt + 1) * mi + cur_min );
}
}
cout << ans << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: