poj 1026 Cipher (置换群)

21 篇文章 0 订阅

链接:poj 1026

题意:给定n个大小1-n的不同的整数作为密钥,给定一个字符串,

      求将该字符串经过k次编码后的字符串

分析:暴力求解会超时,可以利用置换群的知识解题

置换群:一个有限集合的一一变换叫做置换,一对对置换组成了置换群。

对于一个集合a(a[1],a[2],a[3]...a[n]) 通过置换可以变成

     (b[a[1]],b[a[2]],b[a[3]]...b[a[n]]) 

b的作用就是置换(可以理解为某种函数的作用),将原来的集合映射成具有

相应次序的集合a',a'可以看做是a的相同元素集合,不同的排列组合的一个集合

每个n元的置换都可以表示成若干个互不相交的循环置换的乘积,

设每个子循环置换的循环节为ci,则总的置换的循环节显然为lcm(c1,c2..cn)


#include<stdio.h>
#include<string.h>
struct stu{
    int num,period;
}a[205];
int n;
bool visit[205];
void cal_per()        //求每个元素的周期
{
    int t,i;
    memset(visit,false,sizeof(visit));
    for(i=1;i<=n;i++){
        if(!visit[i]){
            visit[i]=true;
            t=a[i].num;
            int cnt=1;
            while(t!=i){
                visit[t]=true;
                cnt++;
                t=a[t].num;
            }
            a[i].period=cnt;
            t=a[i].num;
            while(t!=i){
                a[t].period=cnt;
                t=a[t].num;
            }
        }
    }
}
int main()
{
    char s[205],c,temp;
    int i,j,k,next;
    while(scanf("%d",&n)!=EOF){
        if(n==0)
            break;
        for(i=1;i<=n;i++)
            scanf("%d",&a[i].num);
        cal_per();
        while(scanf("%d",&k)&&k){
            gets(s);
            for(i=strlen(s);i<=n;i++)
                s[i]=' ';
            s[n+1]=0;
            memset(visit,0,sizeof(visit));
            for(i=1;i<=n;i++){
                if(!visit[i]){
                    for(j=1;j<=k%a[i].period;j++){
                        c=s[a[i].num];
                        s[a[i].num]=s[i];
                        visit[i]=true;
                        next=a[i].num;
                        while(next!=i){
                            visit[next]=true;
                            temp=s[a[next].num];
                            s[a[next].num]=c;
                            c=temp;
                            next=a[next].num;
                        }
                    }
                }
            }
            /*for(i=1;i<=n;i++)
                printf("%c",s[i]);
            printf("\n");*/
            puts(s+1);
        }
        printf("\n");
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值