ZOJ 2565 Cracking SSH

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

U(p) = | a[1] - t[p1][p2] | + | a[2] - t[p2][p3] | + . . . + | a[l-1] - t[pl-1][pl] |

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 1
Sample 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;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值