Description
Famous secure shell (ssh) protocol is often used to provide remote access to Unix systems. In ssh protocol all communcations with the server are encrypted using a strong cipher, so it is considered essentially impossible to eavesdrop them.
However, cryptoanalysts have recently found a vulnerability that can be used to learn the user's password when the ssh session is established. The drawback is that when the characters are typed slowly, it is possible that each character is sent to the server in his own network packet. Analyzing the time intervals between consecutive packets and comparing them to typical intervals between typing various characters by the user, it may be possible to determine the most probable password.
You are given the time intervals between consecutive packets in some password sending session and the typical intervals between typing all possible pairs of characters. Your task is to determine the most probable password, assuming that each character of the password was sent in its own packet.
The probability of some string to be the password is determined in the following way. Let the sequence of time intervals given be a[1], a[2], ... , a[l-1]. Let the typical time interval between typing characters c and d be t[c][d]. For the password p = p1p2...pl its unlikeness to the given intervals sequence is
The less is the unlikeness of the password -- the more probable it is.
Input:
The input consists of several test cases
The first line of each test case contains l -- the length of the password, and m -- the number of different characters that can be used in password (2 <= l <= 100, 2 <= m <= 26). The characters used in the password are the first m small letters of the English alphabet.
The second line of each test case contains l-1 integer numbers: a[1], a[2], ... , a[l-1] (1 <= a[i] <= 1000). The following m lines contain m integer numbers each and represent the typical intervals between typing the characters, j-th number of the i-th line is the interval between typing i-th and j-th characters of the alphabet (1 <= t[i][j] <= 1000).
Output:
For each test case, output the most probable password in a line. If there are several possible answers, output any one.
Sample Input:7 3 3 4 4 6 3 5 1 3 4 5 1 2 6 3 1Sample Output:
abacaba动态规划
dp[i][j]表示在第i位输入第j个字母的最小U(p)值。但是单纯的DP只能求出最小的U(p)而不能求出方案,所以用了一个father[i][j]函数来记录是由哪一个状态转移过来的。本来father[i][j]应该记录一个二元组,但是显然i只能由i-1转移过来,所以只用记录一个值。dp[i][j]就是由dp[i-1][father[i][j]]转移的。这样就可以通过father回溯地找到方案了。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
int dp[110][30],N,M,a[110],t[30][30],father[110][30];
void readdata()
{
memset(t,0x3f,sizeof(t));
for(int i=1;i<=N;i++) scanf("%d",&a[i]);
for(int i=1;i<=M;i++)
for(int j=1;j<=M;j++)
scanf("%d",&t[i][j]);
}
void work()
{
memset(dp,0x3f,sizeof(dp));
memset(father,0,sizeof(father));
for(int i=1;i<=M;i++) dp[1][i]=0;
for(int i=2;i<=N+1;i++)//枚举时间
for(int j=1;j<=M;j++)//枚举现在打的字
for(int k=1;k<=M;k++)//枚举上一时刻打的字
if(dp[i][j]>dp[i-1][k]+abs(t[k][j]-a[i-1]))
{
dp[i][j]=dp[i-1][k]+abs(t[k][j]-a[i-1]);
father[i][j]=k;
}
int min=0x3f3f3f3f,minj;
for(int i=1;i<=M;i++) if(min>dp[N+1][i]){minj=i;min=dp[N+1][i];}
char s[110]="";int j=minj;
for(int i=N+1;i>=1;i--)
{
s[i]=j+96;
j=father[i][j];
}
for(int i=1;i<=N+1;i++)printf("%c",s[i]);
}
int main()
{
while(scanf("%d%d",&N,&M)==2)
{
N--;
readdata();
work();
printf("\n");
}
return 0;
}