概述
传送门
Problem Description
在 dota2 中有一个叫做祈求者(Invoker)的英雄,在游戏中他有三个基础技能:冰(Quas),雷(Wex),火(Exort),每施展一个技能就可以获得相应属性的一个法球(element)。
但是祈求者同时最多只能有三个法球,即如果他在有三个法球的状态下又使用了某个法球技能,那么他会获得该法球,并失去之前三个法球中最先获得的一个。
不难得出,祈求者身上的三个法球的无顺序组合有 10 种,每一种都对应着一个组合技能:
- 急速冷却(Cold Snap),无序组合 QQQ,用 Y 表示
- 幽灵漫步(Ghost Walk),无序组合 QQW,用 V 表示
- 寒冰之墙(Ice Wall),无序组合 QQE,用 G 表示
- 电磁脉冲(EMP),无序组合 WWW,用 C 表示
- 强袭飓风(Tornado),无序组合 QWW,用 X 表示
- 灵动迅捷(Alacrity),无序组合 WWE,用 Z 表示
- 阳炎冲击(Sun Strike),无序组合 EEE,用 T 表示
- 熔炉精灵(Forge Spirit),无序组合 QEE,用 F 表示
- 混沌陨石(Chaos Meteor),无序组合 WEE,用 D 表示
- 超震声波(Deafening Blast),无序组合 QWE,用 B 表示
当祈求者拥有三个法球的时候,使用元素祈唤(Invoke)技能,用 R 表示,便可获得当前法球组合所对应的技能,同时原有的三个法球也不会消失,先后顺序的状态也不会改变。
现在给定一个技能序列,你想按照给定的顺序将他们一个一个地祈唤出来,同时你想用最少的按键来达到目标,所以你想知道对于给定的一个技能序列,最少按多少次键才能把他们都祈唤出来。
注意:游戏开始的时候,祈求者是没有任何法球的。
Input
仅一行一个字符串 s,表示技能序列。其中所有字母都是大写,且在 {B,C,D,F,G,T,V,X,Y,Z} 内。
1≤|s|≤105
Output
仅一行一个正整数,表示最少按键次数。
Sample Input
XDTBV
Sample Output
14
思路:递推,首先,基础按键数是字符串的长度,即每个技能都需要按 ‘R’ 释放。其次,每个技能,最多有六种组合方式。dp[i][j]表示在第i个技能选第j种组合方式的情况下,前i个技能所需最少按键数。 对于每个i,暴力枚举上一个技能和当前技能的所有可能的组合方式,他们上一个的后缀和当前的前缀重合的越多,所需按键数越少,分别计算得出第i个技能在六种组合方式下的最少按键数,最后枚举取最少的即可。
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
using namespace std;
#define inf 0x3f3f3f3f
const int N = 1e5+10;
int dp[N][10];
char a[15][6][4]=
{
{"QQQ","QQQ","QQQ","QQQ","QQQ","QQQ"},
//为了枚举方便,不满6个的补满即可
{"QQW","QWQ","WQQ","QQW","QQW","QQW"},
{"QQE","QEQ","EQQ","QQE","QQE","QQE"},
{"WWW","WWW","WWW","WWW","WWW","WWW"},
{"QWW","WQW","WWQ","QWW","QWW","QWW"},
{"WWE","WEW","EWW","WWE","WWE","WWE"},
{"EEE","EEE","EEE","EEE","EEE","EEE"},
{"QEE","EQE","EEQ","QEE","QEE","QEE"},
{"WEE","EWE","EEW","WEE","WEE","WEE"},
{"QWE","QEW","EQW","EWQ","WQE","WEQ"}
};
int cal(string s1,string s2)
{
if(s1==s2) return 0;
if(s1[1]==s2[0]&&s1[2]==s2[1]) return 1;
if(s1[2]==s2[0]) return 2;
return 3;
}
int main()
{
cin.tie(0);
ios::sync_with_stdio(false);
string s;
map<char,int> mp;
mp['Y']=0;mp['V']=1;mp['G']=2;mp['C']=3;mp['X']=4;
mp['Z']=5;mp['T']=6;mp['F']=7;mp['D']=8;mp['B']=9;
mp['.']=10;
while(cin>>s)
{
int n=s.size();s=" "+s;
int ans=n;
memset(dp,inf,sizeof dp);
for(int i=0;i<6;i++)
dp[1][i]=3;
for(int i=2;i<=n;i++)
for(int j=0;j<6;j++)
for(int k=0;k<6;k++)
dp[i][j]=min(dp[i][j],dp[i-1][k]+cal(a[mp[s[i-1]]][k],a[mp[s[i]]][j]));
int x=inf;
for(int i=0;i<6;i++)
x=min(x,dp[n][i]);
cout<<ans+x<<endl;
}
return 0;
}
最后
以上就是懦弱小鸽子为你收集整理的2019ccpc秦皇岛 Invoker(dp / 递推)的全部内容,希望文章能够帮你解决2019ccpc秦皇岛 Invoker(dp / 递推)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复