题意:
对于我这种不玩游戏的人来说,理解题目大意花了好久的时间。
以下题目大意引用自此博客
在 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 表示,便可获得当前法球组合所对应的技能,同时原有的三个法球也不会消失,先后顺序的状态也不会改变。
现在给定一个技能序列,你想按照给定的顺序将他们一个一个地祈唤出来,同时你想用最少的按键来达到目标,所以你想知道对于给定的一个技能序列,最少按多少次键才能把他们都祈唤出来。
注意:游戏开始的时候,祈求者是没有任何法球的。
分析:
首先确定状态,因为序列是无序的,所以对于要产生的一个字符,有6种对应的组合(假设所有的字符均不相同)。
\(dp[i][j]\):表示产生序列中第 \(i\) 个位置的字符对应的第 \(j\) 中序列所需的操作数。
状态转移方程:\(dp[i][j]=min(dp[i][j],dp[i-1][k]+cal(ss[i],ss[i-1],j,k)+1);\)
其中 \(cal()\),表示通过对比产生第 \(i\) 和 \(i-1\) 位置的字符对应的第 \(j\) 和 第 \(k\) 种序列的差别,来确定操作的次数。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
const int inf=0x3f3f3f3f;
char ss[N];
int dp[N][7],p[6][3]={0,1,2,0,2,1,1,0,2,1,2,0,2,1,0,2,0,1};//序列位置的排列方式
map<char,string>mp;
void init()
{
mp['Y']="QQQ";
mp['V']="QQW";
mp['G']="QQE";
mp['C']="WWW";
mp['X']="QWW";
mp['Z']="WWE";
mp['T']="EEE";
mp['F']="QEE";
mp['D']="WEE";
mp['B']="QWE";
}
int cal(char c1,char c2,int x,int y)
{//注意比较的位置
string s=mp[c1];
string t=mp[c2];
if(s[p[x][0]]==t[p[y][0]]&&s[p[x][1]]==t[p[y][1]]&&s[p[x][2]]==t[p[y][2]])
return 0;
else if(s[p[x][0]]==t[p[y][1]]&&s[p[x][1]]==t[p[y][2]])
return 1;
else if(s[p[x][0]]==t[p[y][2]])
return 2;
else return 3;
}
int main()
{
init();
while(scanf("%s",ss+1)!=EOF)
{
int len=strlen(ss+1);
memset(dp,inf,sizeof(dp));
for(int i=0;i<6;i++) dp[1][i]=4;
for(int i=2;i<=len;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(ss[i],ss[i-1],j,k)+1);
}
}
int ans=inf;
for(int i=0;i<6;i++)
ans=min(ans,dp[len][i]);
printf("%d\n",ans);
}
return 0;
}