Invoker CCPC DP
思路: "YVG…"代表不同的技能,每个技能有对应的三个按键,按键的顺序任意,每次需要按下R才能发动技能,发动完技能已有的按键不会消失,每次最多存三个按键(R不算)。求最少的按键次数。
比如YV代表两个技能QQQ和QQW, 我们只需要QQQRWR,就可以。
因为按键可以保留,那么我们尽量让本次的按键对下次技能的按键保留的最多。
但是由于技能之间的按键顺序可以任意,所以我们dp按键组合。
因为一个技能有三个键,所以可以产生六种排序方式(完全相同的也算上)。
dp[i][j]表示第i个技能使用第j种排序方式的按键数,这样我们可以得出方程dp[i][j]=min(dp[i][j],dp[i-1][k]+(第i-1个技能使用第j种排序方式和第i个技能使用第k种排序方式的差值))。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+10; 4 const int inf=0x3f3f3f3f; 5 char a[maxn]; 6 int dp[maxn][10]; 7 map<int,int>mp; 8 char dic[10][6][4] = { // 十个特殊技能的各自的6种组合,少于6种的也给他补全 9 {"QQQ","QQQ","QQQ","QQQ","QQQ","QQQ"}, 10 {"QQW","QWQ","WQQ","WQQ","WQQ","WQQ"}, 11 {"QQE","QEQ","EQQ","EQQ","EQQ","EQQ"}, 12 {"WWW","WWW","WWW","WWW","WWW","WWW"}, 13 {"QWW","WQW","WWQ","WWQ","WWQ","WWQ"}, 14 {"WWE","WEW","EWW","EWW","EWW","EWW"}, 15 {"EEE","EEE","EEE","EEE","EEE","EEE"}, 16 {"QEE","EQE","EEQ","EEQ","EEQ","EEQ"}, 17 {"WEE","EWE","EEW","EEW","EEW","EEW"}, 18 {"QWE","QEW","EQW","EWQ","WEQ","WQE"}, 19 }; 20 int cal(int x,int y,int pos1,int pos2) 21 { 22 if(dic[x][pos1][0]==dic[y][pos2][0]&&dic[x][pos1][1]==dic[y][pos2][1]&& 23 dic[x][pos1][2]==dic[y][pos2][2]) return 0; 24 if(dic[x][pos1][0]==dic[y][pos2][1]&&dic[x][pos1][1]==dic[y][pos2][2]) 25 return 1; 26 if(dic[x][pos1][0]==dic[y][pos2][2]) return 2; 27 return 3; 28 } 29 int main() 30 { 31 mp['Y'] = 0; mp['V'] = 1; mp['G'] = 2; mp['C'] = 3; mp['X'] = 4; 32 mp['Z'] = 5; mp['T'] = 6; mp['F'] = 7; mp['D'] = 8; mp['B'] = 9; 33 scanf("%s",a); 34 int len=strlen(a); 35 memset(dp,inf,sizeof(dp)); 36 dp[0][0]=dp[0][1]=dp[0][2]=dp[0][3]=dp[0][4]=dp[0][5]=3; 37 for(int i=1;i<len;i++){ 38 for(int j=0;j<6;j++){ 39 for(int k=0;k<6;k++){ 40 dp[i][j]=min(dp[i][j],dp[i-1][k]+cal(mp[a[i]],mp[a[i-1]],j,k)); 41 } 42 } 43 } 44 int mn=inf; 45 for(int i=0;i<6;i++){ 46 mn=min(mn,dp[len-1][i]); 47 } 48 printf("%d\n",mn+len); 49 return 0; 50 }