置换群题目汇总

首先介绍一下什么是置换群,不说一些繁琐的概念。

首先给你一个序列,假如:

s = {1 2 3 4 5 6}

然后给你一个变换规则

t = {6 3 4 2 1 5}

就是每一次按照t规则变换下去

比如这样

第一次:6 3 4 2 1 5

第二次:5 4 2 3 6 1

第三次:1 2 3 4 5 6

发现经过几次会变换回去,在变换下去就是循环的了,这就是一个置换群。

我们可以这样表示一个置换群,比如按照上面变化规则

1->6->5->1 那么这些是一个轮换

2->3->4->2 这些是一个轮换

所以可以写为

t = { {1 6 5},{ 2 3 4 } },然后就衍生出了一些这样的题目

1: nyoj900序列置换

就是求置换群的的一个循环,那么很明显,我们求出置换群中的所有轮换的元素个数,求最小公倍数即可,注意这个题目会超int,坑…

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 300;
const int inf = 0x3f3f3f3f;
typedef long long LL;
int next[N];
bool ok[N];
LL gcd(LL a,LL b)
{
    return b==0?a:gcd(b,a%b);
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&next[i]);
        }
        LL ans = 1;
        memset(ok,false,sizeof(ok));
        for(int i=1;i<=n;i++)
        {
            if(ok[i]==false)
            {
                int tmp = i;
                LL cnt = 1;
                ok[i] = true;
                while(next[tmp]!=i)
                {
                    cnt++;
                    tmp = next[tmp];
                    ok[tmp] = true;
                }
                LL css = gcd(ans,cnt);
                ans = (ans*cnt)/css;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

2:poj3270 Cow Sorting

题意是给你一个序列s = {a1,a2……an},然后可以任意交换其中两个元素 i , j 的位置,代价是位ai + aj,然后让你把这个序列变成有序,求最小代价

思路:对置换群的巧妙应用

首先我们求出所有轮换,对于一个轮换,我们用其中最小的元素去交换得到其他的显然是最优的方案。

例如,数字是8 4 5 3 2 7

明显,目标状态是2 3 4 5 7 8,能写为两个轮换:(8 2 7)(4 3 5)。

观察其中一个轮换,要使交换代价最小,应该用循环里面最小的数字2,去与另外的两个数字,7与8交换。这样交换的代价是:

sum - min + (len - 1) * min

化简后为:

sum + (len - 2) * min

其中,sum为这个循环所有数字的和,len为长度,min为这个环里面最小的数字。

.考虑到另外一种情况,我们可以从别的循环里面调一个数字,进入这个循环之中,使交换代价更小。例如初始状态:1 8 9 7 6

可分解为两个循环:(1)(8 6 9 7),明显,第二个循环为(8 6 9 7),最小的数字为6。我们可以抽调整个数列最小的数字1进入这个循环。使第二个循环变为:(8 1 9 7)。让这个1完成任务后,再和6交换,让6重新回到循环之后。这样做的代价明显是:

sum + min + (len + 1) * smallest

其中,sum为这个循环所有数字的和,len为长度,min为这个环里面最小的数字,smallest是整个数列最小的数字。

那么就很明朗了。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 10010;
const int inf = 0x3f3f3f3f;
int pss[N];
int a[N];
bool ok[10*N];
int next[10*N];

int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        memset(ok,true,sizeof(ok));
        int mi = inf,ma = -1;
        for(int i=1;i<=n;i++){
            scanf("%d",&pss[i]);
            a[i] = pss[i];
            mi = min(mi,pss[i]);
            ma = max(ma,pss[i]);
            ok[ pss[i] ] = false;
        }
        sort(a+1,a+1+n);
        for(int i=1;i<=n;i++)
        {
            next[ a[i] ] = pss[i];
        }
        int ans = 0;
        for(int i=1;i<=ma;i++)
        {
            if(ok[next[i] ] == false)
            {
                int num = i, tmpmi = i;
                int cnt = 1,count = i;
                ok[num] = true;
                while(next[num]!=i)
                {
                    num = next[num];
                    cnt++;
                    count+=num;
                    ok[num] = true;
                    tmpmi = min(tmpmi,num);
                }
                ans+=min(count+(cnt-2)*tmpmi,count+tmpmi+(cnt+1)*mi);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
还有一道比较牛的题目,用到扩展欧几里得,还没有做出来,后面更新
时间: 2024-11-09 00:47:51

置换群题目汇总的相关文章

剑指 Offer 题目汇总索引

剑指 Offer 总目录:(共50道大题) 1. 赋值运算符函数(或应说复制拷贝函数问题) 2. 实现 Singleton 模式 (C#) 3.二维数组中的查找 4.替换空格               时间:O(n) 空间:O(1) 5.从尾到头打印链表 6. 重建二叉树          && 二叉树的各种遍历(BFS,DFS,DLR,LDR,LRD) 7.用两个栈实现队列 8.旋转数组的最小数字 9.斐波那契数列第 n 项        时间O(lgn) 10.一个整数的二进制表示中

HTML5面试题目汇总(二)

HTML5面试题目汇总(二) 标签: javascript 2016-07-19 10:15 639人阅读 评论(0) 收藏 举报  分类: javascript(16)  1.怎样添加.移除.移动.复制.创建和查找节点? 1)创建新节点 createDocumentFragment() //创建一个DOM片段 createElement() //创建一个具体的元素 createTextNode() //创建一个文本节点 2)添加.移除.替换.插入 appendChild() //添加 remo

线段树题目汇总

区间合并部分: POJ 3667 Hotel 求某大于等于a的最长区间 #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #define LEN 50001<<2 using namespace std; struct Line_tree { //分别表示以当前区间为左端点的最长连续空白区间,为右端点的最长连续空白区间,该区间的最长连续空白区

NYOJ 搜索题目汇总 NYOJ 20、21、27、42、58、82、202、284、325、353、488、491、523、592、722

NYOJ 搜索题目汇总 NYOJ 20 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<vector> #include<algorithm> using namespace std; int pre[100005]; vector<int>v[100005];//存储每个结点相邻的边 void DFS(int

力扣题目汇总(加一,旋转数组,整数反转)

力扣题目汇总(加一,旋转数组,整数反转) 加一 1.题目描述 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一. 最高位数字存放在数组的首位, 数组中每个元素只存储一个数字. 你可以假设除了整数 0 之外,这个整数不会以零开头. 示例 1: 输入: [1,2,3] 输出: [1,2,4] 解释: 输入数组表示数字 123. 示例 2: 输入: [4,3,2,1] 输出: [4,3,2,2] 解释: 输入数组表示数字 4321. 2.解题思路 #错误思路 列表最后一位加1,判断最后

力扣题目汇总(转换成小写字母,唯一摩尔斯密码,有序数组平方)

力扣题目汇总(转换成小写字母,唯一摩尔斯密码,有序数组平方) 转换成小写字母 1.题目描述 实现函数 ToLowerCase(),该函数接收一个字符串参数 str,并将该字符串中的大写字母转换成小写字母,之后返回新的字符串. 示例 1: 输入: "Hello" 输出: "hello" 示例 2: 输入: "here" 输出: "here" 示例 3: 输入: "LOVELY" 输出: "lovel

2019最新Android中级面试题目汇总解答

注:因为实际开发与参考答案会有所不同,再者怕误导大家,所以这些面试题答案还是自己去理解!面试官会针对简历中提到的知识点由浅入深提问,所以不要背答案,多理解. Android进阶延伸点 1.如何进行单元测试,如何保证App稳定 ? 参考回答: 要测试Android应用程序,通常会创建以下类型自动单元测试 本地测试:只在本地机器JVM上运行,以最小化执行时间,这种单元测试不依赖于Android框架,或者即使有依赖,也很方便使用模拟框架来模拟依赖,以达到隔离Android依赖的目的,模拟框架如Goog

LeetCode 11月第2周题目汇总

开源地址:点击该链接 前言 最近比较忙,这周几乎没有刷题,只刷了6道题~ 题目汇总 0387_first_unique_character_in_a_string类似的题目比较多了,字符串中找出特别的那一个,由于字符串数目有限,所以直接使用哈希表即可,使用 unordered_map 会有点慢,直接使用数组比较快:第一次遍历统计每个字符的数量,第二次遍历找出第一个只出现一次的字符即可. 0389_find_the_difference题目是找出两个字符串中唯一一个不同的字符是什么,这个题目和 0

测试开发面试题目汇总一

测试开发面试题目汇总 1. 项目经验 2. 测试的过程 3. 京东登录页面怎么测? 4. 如果一个普通用户,他的百度首页打不开,问题怎么定位?写出定位流程. 5.问简历上的第一个项目的详细情况,包括测试用例怎么写?怎么判断测试通过?项目的原理? 6.如果是做功能测试,能接受吗? 7.说一下你们工作中的测试流程 8.用她的手机给我看了下百度贴吧的发帖功能的界面,给我张纸,让我写出测试点(只需要考虑内容,表情,添加图片,@功能),写完讲一遍逻辑. 9  针对发朋友圈这个功能设计你的测试用例,请给出用