poj3898 Software Industry Revolution

本文探讨了软件行业的革新,特别关注了Stanescu所发明的一种独特软件开发方式,即通过请求他人代为编写代码来创建高质量软件,而无需深入了解图灵机的概念。文章进一步阐述了为了保护即将获得的财富,Stanescu需要设计一个特殊的银行账户密码,该密码不仅简单到可以记住,还需要匹配特定模式,并成为超长超级密码字符串的一个子串。本文提供了求解此问题的动态规划算法,详细解释了如何计算最简单可能的密码复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Software Industry Revolution
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 263 Accepted: 86

Description

Making revolutions in the software industry is not an easy task. That’s why this problem is about something else. Stanescu has just invented a new super-cool way to develop software. It is similar to writing program code, but instead of writing it, you ask some else to do it. In such way, one could create great software, without even knowing what a Turing Machine is. As you can see, this is not just software industry revolution. Really, Stanescu does not care about the software industry at all. He just wants to make money. 
In order to protect the money he is going to make, he needs to pick a special password for his bank account, satisfying the following requirements: 


The password should not be too complex, so that Stanescu can remember it. The complexity of a password is the sum of the complexity of its characters and the complexity of a character is its position in the alphabet (for ’a’ it is 1, for ’b’ – 2, and so on). For example, the complexity of the string ”ala” is 1 + 12 + 1 = 14; 
It should match a given pattern string (composed of lowercase Latin letters, ’?’ and ’*’, no longer than 1000 characters). ’?’ is matched by one arbitrary lowercase Latin letter, and ’*’ – by zero or more arbitrary lowercase Latin letters; 
It should be a sub-string of given super-password string (composed of lowercase Latin letters, no longer than 10000). 


You have to write a program that computes the complexity of simplest possible password.

Input

Several test cases are given at the input. Each of them consists of a single line containing the pattern and the super-password strings separated by a white space.

Output

For each test case, your program should print a single line with one integer – the complexity of the simplest possible password. If no password satisfies the given requirements, the program should print -1.

Sample Input

a?a alabala
a*c?a axcbaabcbax

Sample Output

4
9

Hint

Explanation: 
Test case #1: aba is the simplest password 
Test case #2: abcba is simpler than axcba
这题考的是dp,可是我们一般很难写出状态转移方程,看解题报告还要看半天才知道什么意思,这个题我几乎就是copy解题报告的啊,虽然都是自己手打的,哎。。。。就当是解说员吧
/*
dp[i][j]代表模式串的第i个和原串的第j个匹配的时候最小值。
对于?
dp[i][j]=dp[i-1][j-1]+cost[j,j]

对于字母,要求mat[i]==pat[j]才能转移。
dp[i][j]=dp[i-1][j-1]+cost[j,j]
sum[i]代表原串前i个代价的总和
对于*
dp[i][j]=min{dp[i-1][k]+cost[k+1,j]}  for k>=0&&k<=j

对于这个式子的话看起来要枚举K,这样显然不行。
我们可以转化
dp[i-1][k]+cost[k+1,j]
=dp[i-1][k]+sum[j]-sum[k]=(dp[i-1][k]-sum[k])+sum[j]

(dp[i-1][k]-sum[k])这个是一个只和k有关的式子。
我们可以保存一个(dp[i-1][k]-sum[k])最小值。这样就可以o(1)得到dp[i][j]了。
*/
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std; 

char str[1050],pass[10050];
int sum[10050],record[27],dp[1005][10050];

int main ()
{
	int i,j,cur,n,m;
	bool flag;
	while(scanf("%s%s",str+1,pass+1)!=EOF)
	{
		n=strlen(str+1);
		m=strlen(pass+1);
		sum[0]=0;
		for(i=0;i<26;i++)
			record[i]=0;
		for(i=1;i<=m;i++)
		{
			record[pass[i]-'a']++;
		}
		for(i=1;i<=n;i++)
		{
			if(str[i]>='a')//没想到问题出在这,数组越界了oj尽然没提示RE却提示WA
				record[str[i]-'a']--;
		}
		for(i=0;i<26;i++)
		{
			if(record[i]<0)
				break;
		}
		if(i<26)//这是最开始的优化,明显不合题意的去掉
		{
			printf("-1\n");
			continue;
		}
		for(i=1;i<=m;i++)
		{
			sum[i]=pass[i]-'a'+1+sum[i-1];
		}
		for(i=0;i<=n;i++)
			for(j=0;j<=m;j++)
			dp[i][j]=10000000;
		for(i=0;i<=m;i++)//str[1]得特殊操作,给dp[1][j]一个初始值
		{
			if(i>0&&(str[1]=='?'||str[1]==pass[i]))//第一位为?或者和pass[i]相等那dp[1][i]当然就是str[1]对应的值也是sum[i]-sum[i-1]
			{
				dp[1][i]=sum[i]-sum[i-1];
			}
			else if(str[1]=='*')//*有点特殊,它的取值是不定的,但是这题要求最小的值,如果str第一个为*,那我们完全可以不取任何值,也就是0
			{
				dp[1][i]=0;
			}
		}
		for(i=2;i<=n;i++)
		{
			flag=0;
			if(str[i]=='*')
			{
				cur=10000000;
				if(dp[i-1][0]==0)
				{
					flag=1;
					dp[i][0]=0;
					cur=0;//记录一下最小值
				}
				for(j=1;j<=m;j++)
				{
					if(dp[i-1][j]-sum[j]<cur)
						cur=dp[i-1][j]-sum[j];
					if(sum[j]+cur<dp[i][j])
					{
						dp[i][j]=sum[j]+cur;
						flag=1;
					}
				}
			}
			else 
			{
				for(j=1;j<=m;j++)
				{
					if(dp[i-1][j-1]==10000000)
						continue;//简化运算
					if(str[i]=='?'||str[i]==pass[j])
					{
						if(dp[i][j]>dp[i-1][j-1]+pass[j]-'a'+1)
						{
							dp[i][j]=dp[i-1][j-1]+pass[j]-'a'+1;
							flag=1;
						}
					}
				}
			}
			if(!flag)//若flag为0,那就说明上面没有任何操作,没有符合条件的情况了,找不到适合的解了
				break;
		}
		if(i<=n)//程序没有全部执行,str并没有在pass中全部找到
		{
			printf("-1\n");
			continue;
		}
		cur=100000000;
		for(i=0;i<=m;i++)//应该是从零开始,如果str是*结果就是0
		{
			if(cur>dp[n][i])//str中的字母都找完了
				cur=dp[n][i];
		}
		if(cur==100000000)
			printf("-1\n");
		else 
			printf("%d\n",cur);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LittleLoveBoy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值