• 希尔加密算法(湖南师范大学第六届大学生计算机程序设计竞赛)hnuoj11552


    解密

    Time Limit: 1000ms, Special Time Limit:2500ms, Memory Limit:65536KB

    Total submit users: 2, Accepted users: 0

    Problem 11552 : No special judgement

    Problem description

      password学中。有一种加密方法。叫做希尔加密法。

    其加密过程例如以下: 
    Step1:将待加密的字符串s={s[0], s[1], …… ,s[n-1]} (为简单起见。在本题中,字符串s仅仅含小写字母)按a->0, b->1,c->2, ……, y->24, z->25的规则转换为整形数组a={a[0], a[1], …… ,a[n-1]};
    Step2: 将数组a分成长度相等的k个部分,每部分长度均为L(保证k*L=s待加密的字符串s的长度)
    Setp3:将每部分左乘一L * L矩阵A,将结果向量中全部值对26取模后替换原来的部分。得到新的数组 
    b={b[0], b[1], …… ,b[n-1]}, 
    即b中的元素满足: 
    (b[i * k],b[i * k + 1], ……, b[i * k + (L - 1)]) = (a[i * k],a[i * k + 1], ……, a[i * k + (L - 1)])*A
    Step4:将数组b中的数按0->a, 1->b, 2->c, ……, 24->y, 25->z的规则转换为密文 
    比如:加密july,矩阵A=[11 8;3 7](分号表示另起一行)
    Step1:将july转化为数组a={9, 20, 11, 24};
    Step2:将a分为{9, 20}。{11, 24}两部分 
    Step3:因为[9, 20] * [11 8;3 7] = [159, 212]
    [11, 24] * [11 8;3 7]=[193, 256]
    故b=[159 % 26, 212 % 26, 193 % 26, 256 % 26] = [3, 4, 11, 22]
    Step4:密文即为delw
    你的任务是:给你密文和矩阵A。求原字符串 

    Input

      第一行为一个整数T (0 < T < 20), 表示数据的组数.
    每组数据的第一行为一个 仅仅有小写字母构成的 加密后 的字符串, 其长度不超过10000。
    第二行为一个整数M(0 < M <= 100 且 字符串的长度能够整除M),表示矩阵A是M*M的矩阵 
    后面M行。每行M个整数。 表示矩阵A,输入数据保证矩阵A主对角线上的元素与26互素

    Output

      对每组数据,输出一行,为密文所相应的原文

    Sample Input

    2

    delw

    2

    11 8

    3 7

    pabqlzqii

    3

    1 14 2

    5  9 2

    4 7 3

    Sample Output

    july

    qvtusjkcm

    Problem Source

      HUNNU Contest 

    希尔解密。须要先求逆矩阵。

    我仅仅能过第一组。

    。。

    大神们,求解释。。。

    #include <math.h>
    #include <string.h>
    #include <malloc.h>
    #include <iostream>
    #include <iomanip>
    #include<stdio.h>
    using namespace std;
    #define  N  105                //定义方阵的最大阶数为10
    //函数的声明部分
    double MatDet(double *p, int n);                    //求矩阵的行列式
    double Creat_M(double *p, int m, int n, int k);    //求矩阵元素A(m, n)的代数余之式
    void print(double *p, int n);                    //输出矩阵n*n
    bool Gauss(double A[][N], double B[][N], int n);    //採用部分主元的高斯消去法求方阵A的逆矩阵B
    double a[N][N],b[N][N];
    int c[N][N];
    double determ;                //定义矩阵的行列式
    //int zimu[26];
    int gcd(int a,int b)
    {
        if(!b) return a;
        gcd(b,a%b);
    }
    void Print(int mm[],int k)
    {
        /*
        for(int i=0; i<k; i++)
        {
            printf("%d ",mm[i]);
        }
        printf("
    ");*/
        for(int i=0; i<k; i++)
        {
            for(int j=0; j<k; j++)
            {
                printf("%d ",c[i][j]);
            }
            printf("
    ");
        }
       // double tp[105]= {0};
       int tp[105]={0};
        for(int i=0; i<k; i++) //列
        {
            for(int j=0; j<k; j++) //行||mm的行
            {
                tp[i]+=mm[j]*c[j][i];
     //           printf("tp=%d	mm=%d	b=%d
    ",tp[i],mm[j],c[j][i]);
            }
        }
        for(int i=0; i<k; i++)
        {
     //       int tmp=(int)(tp[i]);
     //       printf("%d	",tmp);
            printf("%c",((tp[i])%26+26)%26+'a');
      //      while(tp[i]<0) tp[i]+=26;
      //      printf("%c
    ",(int)(tp[i])%26+'a');
        }
     //   printf("
    ");
    }
    int main()
    {
     //   freopen("xier.txt","r",stdin);
        double *buffer, *p;            //定义数组首地址指针变量
        int row, num;                //定义矩阵的行数和矩阵元素个数
       // int i, j;
    
    
        int n;
    //    for(int i=0;i<26;i++)
    //       zimu[i]=i;
        int T,len,M,mo[105];
        char mi[10005];
        scanf("%d",&T);
        while(T--)
        {
            scanf("%s",mi);
            len=strlen(mi);
            scanf("%d",&n);
            row=n;
            num = 2*row*row;
            buffer = (double *)calloc(num, sizeof(double));        //分配内存单元
            p = buffer;
            for(int i=0; i<n; i++)
            {
                for(int j=0; j<n; j++)
                {
                    scanf("%lf",&a[i][j]);
                    *p++=a[i][j];
                }
            }
            determ = MatDet(buffer, row);    //求整个矩阵的行列式
      //      printf("determ=%lf
    ",determ);
            int d=gcd((int)(determ),27);
            d=(int)determ*27/d;
     //       printf("***************************************d=%d
    ",d);
            for (int i = 0; i < row; i++)    //求逆矩阵
            {
                for (int j = 0; j < row; j++)
                {
                    *(p+j*row+i) = Creat_M(buffer, i, j, row)*d/determ;
                }
            }
            print(p, row);
            free(buffer);        //释放内存空间
            for(int i=0; i<len; i++)
                {
                    //    printf("mi=%c
    ",mi[i]);
                    mo[i%n]=mi[i]-'a';
                    //         printf("i=%d	mo=%d
    ",i%n,mo[i%n]);
                    if((i+1)%n==0) Print(mo,n);
                }
                printf("
    ");
    
     //       for(int i=0; i<n; i++)
     //       {
      //          for(int j=0; j<n; j++)
       //         {
       //             printf("%lf ",a[i][j]);
        //        }
        //        printf("
    ");
        //    }
     //       if(Gauss(a,b,n))
     //       {
                /*
                for (int i = 0; i < n; i++)
                {
                    cout << setw(4);
                    for (int j = 0; j < n; j++)
                    {
                        cout << b[i][j] << setw(10);
                    }
                    cout << endl;
                }*/
    
       //     }
        }
        return 0;
    }
    //-----------------------------------------------
    //功能: 求矩阵(n*n)的行列式
    //入口參数: 矩阵的首地址,矩阵的行数
    //返回值: 矩阵的行列式值
    //----------------------------------------------
    double MatDet(double *p, int n)
    {
        int r, c, m;
        int lop = 0;
        double result = 0;
        double mid = 1;
        if (n != 1)
        {
            lop = (n == 2) ? 1 : n;            //控制求和循环次数,若为2阶,则循环1次。否则为n次
            for (m = 0; m < lop; m++)
            {
                mid = 1;            //顺序求和, 主对角线元素相乘之和
                for (r = 0, c = m; r < n; r++, c++)
                {
                    mid = mid * (*(p+r*n+c%n));
                }
                result += mid;
            }
            for (m = 0; m < lop; m++)
            {
                mid = 1;            //逆序相减, 减去次对角线元素乘积
                for (r = 0, c = n-1-m+n; r < n; r++, c--)
                {
                    mid = mid * (*(p+r*n+c%n));
                }
                result -= mid;
            }
        }
        else
            result = *p;
        return result;
    }
    //----------------------------------------------------------------------------
    //功能: 求k*k矩阵中元素A(m, n)的代数余之式
    //入口參数: k*k矩阵的首地址。矩阵元素A的下标m,n,矩阵行数k
    //返回值: k*k矩阵中元素A(m, n)的代数余之式
    //----------------------------------------------------------------------------
    double Creat_M(double *p, int m, int n, int k)
    {
        int len;
        int i, j;
        double mid_result = 0;
        int sign = 1;
        double *p_creat, *p_mid;
        len = (k-1)*(k-1);            //k阶矩阵的代数余之式为k-1阶矩阵
        p_creat = (double*)calloc(len, sizeof(double)); //分配内存单元
        p_mid = p_creat;
        for (i = 0; i < k; i++)
        {
            for (j = 0; j < k; j++)
            {
                if (i != m && j != n) //将除第i行和第j列外的全部元素存储到以p_mid为首地址的内存单元
                {
                    *p_mid++ = *(p+i*k+j);
                }
            }
        }
        sign = (m+n)%2 == 0 ?

    1 : -1; //代数余之式前面的正、负号 mid_result = (double)sign*MatDet(p_creat, k-1); free(p_creat); return mid_result; } //----------------------------------------------------- //功能: 打印n*n矩阵 //入口參数: n*n矩阵的首地址,矩阵的行数n //返回值: 无返回值 //----------------------------------------------------- void print(double *p, int n) { int i, j; for (i = 0; i < n; i++) { // cout << setw(4); for (j = 0; j < n; j++) { c[i][j]=(int)*p++; while(c[i][j]<0) c[i][j]+=26; // cout << setiosflags(ios::right) << *p++ << setw(10); } // cout << endl; } } //------------------------------------------------------------------ //功能: 採用部分主元的高斯消去法求方阵A的逆矩阵B //入口參数: 输入方阵,输出方阵,方阵阶数 //返回值: true or false //------------------------------------------------------------------- bool Gauss(double A[][N], double B[][N], int n) { int i, j, k; double max, temp; double t[N][N]; //暂时矩阵 //将A矩阵存放在暂时矩阵t[n][n]中 for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { t[i][j] = A[i][j]; } } //初始化B矩阵为单位阵 for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { B[i][j] = (i == j) ? (double)1 : 0; } } for (i = 0; i < n; i++) { //寻找主元 max = t[i][i]; k = i; for (j = i+1; j < n; j++) { if (fabs(t[j][i]) > fabs(max)) { max = t[j][i]; k = j; } } //假设主元所在行不是第i行,进行行交换 if (k != i) { for (j = 0; j < n; j++) { temp = t[i][j]; t[i][j] = t[k][j]; t[k][j] = temp; //B伴随交换 temp = B[i][j]; B[i][j] = B[k][j]; B[k][j] = temp; } } //推断主元是否为0, 若是, 则矩阵A不是满秩矩阵,不存在逆矩阵 if (t[i][i] == 0) { cout << "There is no inverse matrix!"; return false; } //消去A的第i列除去i行以外的各行元素 temp = t[i][i]; for (j = 0; j < n; j++) { t[i][j] = t[i][j] / temp; //主对角线上的元素变为1 B[i][j] = B[i][j] / temp; //伴随计算 } for (j = 0; j < n; j++) //第0行->第n行 { if (j != i) //不是第i行 { temp = t[j][i]; for (k = 0; k < n; k++) //第j行元素 - i行元素*j列i行元素 { t[j][k] = t[j][k] - t[i][k]*temp; B[j][k] = B[j][k] - B[i][k]*temp; } } } } for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { B[i][j]*=determ; } //printf(" "); } return true; }


     

  • 相关阅读:
    关于extern的用法
    建立CMenu菜单项,实现选中菜单项点击左键响应事件
    数据库常用语句
    圆周率的计算
    C++11中list特有版本的算法
    使用istream迭代器来输入输出数据
    C++中函数重载和函数覆盖的区别
    外置接口请求
    JSON转指定复杂对象
    FastDFS优化
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/6904365.html
Copyright © 2020-2023  润新知