希尔加密算法(湖南师范大学第六届大学生计算机程序设计竞赛)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

  密码学中,有一种加密方法,叫做希尔加密法。其加密步骤如下: 
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("\n");*/
    for(int i=0; i<k; i++)
    {
        for(int j=0; j<k; j++)
        {
            printf("%d ",c[i][j]);
        }
        printf("\n");
    }
   // 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\tmm=%d\tb=%d\n",tp[i],mm[j],c[j][i]);
        }
    }
    for(int i=0; i<k; i++)
    {
 //       int tmp=(int)(tp[i]);
 //       printf("%d\t",tmp);
        printf("%c",((tp[i])%26+26)%26+'a');
  //      while(tp[i]<0) tp[i]+=26;
  //      printf("%c\n",(int)(tp[i])%26+'a');
    }
 //   printf("\n");
}
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\n",determ);
        int d=gcd((int)(determ),27);
        d=(int)determ*27/d;
 //       printf("***************************************d=%d\n",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\n",mi[i]);
                mo[i%n]=mi[i]-'a';
                //         printf("i=%d\tmo=%d\n",i%n,mo[i%n]);
                if((i+1)%n==0) Print(mo,n);
            }
            printf("\n");

 //       for(int i=0; i<n; i++)
 //       {
  //          for(int j=0; j<n; j++)
   //         {
   //             printf("%lf ",a[i][j]);
    //        }
    //        printf("\n");
    //    }
 //       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("\n");
    }
    return true;
}


 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值