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} }
接触到置换群的概念,对于一个(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; }
相关文章推荐
- GBDT(MART)迭代决策树入门教程|简介
- altera FPGA学习日记
- jQuery中checkbo添加事件,判断是否选中和设置选中与取消选中
- 枚举
- Light OJ 1422 Halloween Costumes(区间DP)
- C++ 和 lua代码互相调用
- 用友T6 操作发票凭证时 portal.exe发生未处理的win32异常,弹出vistual studio实时调试器
- C++内存对象大会战
- 程序员面试题目:Cracking the coding interview 分析与解答
- Lanterns
- Android消息推送
- 【C语言】把从1到1000的数打印出来,但你不能使用任何的循环语句或是条件语句。
- 类型转换
- scal实现工厂方法模式
- Task schedule
- 类似微信的文本输入框
- Unity NGUI实现2048(二)逻辑分析
- 使用Markdown写博客
- Task schedule 分类: 比赛 HDU 查找 2015-08-08 16:00 2人阅读 评论(0) 收藏
- rt: Unknown command 'PATH='