最高分 | ||||||
| ||||||
Description | ||||||
小胖子玩游戏,游戏规则是给定一个字符串:在一个字符串中如果有两个相邻的字符满足是x,y,那么就可以得到c(x,y)的分数。为了得到更高的分数,小胖子可以对字符串更改k次,每次只能改动一个字符。请问小胖子最多能得多少分。 | ||||||
Input | ||||||
本题有多组测试数据,每组测试数据占n+2行。 | ||||||
Output | ||||||
对于每组测试数据输出小胖子的最高得分。 | ||||||
Sample Input | ||||||
winner 4 4 s e 7 o s 8 l o 13 o o 8 | ||||||
Sample Output | ||||||
36 | ||||||
Hint | ||||||
对于第一组测试数据,将“winner”变成“looser”,就可以得到最高得分36。 | ||||||
Author | ||||||
sunshine@hrbust |
思路:
1、首先吐槽一下后台数据,对应后台数据中,输入:
winner 0
4
w i 10
w i 9
w i 8
w i 7
输出的结果是7.................................
2、设定dp【i】【j】【k】表示对应dp到第i位,当前字母是j(j==0代表是字母a),已经改变了k次字母的情况下的最大值。
辣么不难想到其状态转移方程:
①if(a【i】==j)dp【i】【j】【k】=max(dp【i】【j】【k】,dp【i-1】【q】【k】+map【q】【j】)表示当前情况可以从:dp到第i-1位,那一位字母是q,已经改变了k次字母的情况下的最大值,这一状态转移过来。维护最大值。
②else dp【i】【j】【k】=max(dp【i】【j】【k】,dp【i-1】【q】【k-1】+map【q】【j】)表示当前状态可以从:dp到第i-1位,那一位字母是q,已经改变了k-1次字母的情况下的最大值,这一状态转移过来。维护最大值。
③时间复杂度:O(len*26*k*26),5000ms是可以撑得住的.
3、注意初始化,注意数组不要非法越界。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int map[30][30];
int dp[150][26][150];
char a[15151];
int kk;
void Slove()
{
int n=strlen(a);
for(int i=0;i<n;i++)
{
for(int j=0;j<26;j++)
{
for(int k=0;k<=kk;k++)
{
dp[i][j][k]=-0x3f3f3f3f;
}
}
}
for(int i=0;i<26;i++)
{
if(i==a[0]-'a')dp[0][i][0]=0;
else dp[0][i][1]=0,dp[0][i][0]=-0x3f3f3f3f;
}
for(int i=1;i<n;i++)
{
for(int j=0;j<26;j++)
{
if(j==a[i]-'a')
{
for(int k=0;k<=i&&k<=kk;k++)
{
for(int q=0;q<26;q++)
dp[i][j][k]=max(dp[i][j][k],dp[i-1][q][k]+map[q][j]);
}
}
else
{
for(int k=1;k<=i+1&&k<=kk;k++)
{
for(int q=0;q<26;q++)
{
dp[i][j][k]=max(dp[i][j][k],dp[i-1][q][k-1]+map[q][j]);
}
}
}
}
}
}
int main()
{
while(~scanf("%s%d",&a,&kk))
{
int m;
memset(map,0,sizeof(map));
scanf("%d",&m);
while(m--)
{
char u[3],v[3];
int c;
scanf("%s%s%d",u,v,&c);
map[u[0]-'a'][v[0]-'a']=c;
}
memset(dp,0,sizeof(dp));
Slove();
int output=-0x3f3f3f3f;
int n=strlen(a);
for(int i=0;i<26;i++)
{
for(int j=0;j<=kk;j++)
{
output=max(output,dp[n-1][i][j]);
}
}
printf("%d\n",output);
}
}