標籤:湖南師範大學第六屆大學生電腦程式設計競 希爾解密
解密 |
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*nbool Gauss(double A[][N], double B[][N], int n); //採用部分主元的高斯消去法求方陣A的逆矩陣Bdouble 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;}
希爾密碼編譯演算法(湖南師範大學第六屆大學生電腦程式設計競賽)hnuoj11552