2019ccpc秦皇島 Invoker(dp / 遞推)

傳送門

Problem Description
在 dota2 中有一個叫做祈求者(Invoker)的英雄,在遊戲中他有三個基礎技能:冰(Quas),雷(Wex),火(Exort),每施展一個技能就可以獲得相應屬性的一個法球(element)。

但是祈求者同時最多隻能有三個法球,即如果他在有三個法球的狀態下又使用了某個法球技能,那麼他會獲得該法球,並失去之前三個法球中最先獲得的一個。

不難得出,祈求者身上的三個法球的無順序組合有 10 種,每一種都對應着一個組合技能:

  1. 急速冷卻(Cold Snap),無序組合 QQQ,用 Y 表示
  2. 幽靈漫步(Ghost Walk),無序組合 QQW,用 V 表示
  3. 寒冰之牆(Ice Wall),無序組合 QQE,用 G 表示
  4. 電磁脈衝(EMP),無序組合 WWW,用 C 表示
  5. 強襲颶風(Tornado),無序組合 QWW,用 X 表示
  6. 靈動迅捷(Alacrity),無序組合 WWE,用 Z 表示
  7. 陽炎衝擊(Sun Strike),無序組合 EEE,用 T 表示
  8. 熔爐精靈(Forge Spirit),無序組合 QEE,用 F 表示
  9. 混沌隕石(Chaos Meteor),無序組合 WEE,用 D 表示
  10. 超震聲波(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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章