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