题意:
就是魔法召唤技能,最少的符号数之类的。
思路:
线性dp题
记 dp[i][6] 为祈唤出第 i 个技能之后,身上三个法球的先后顺 序为 0 ∼ 5 的状态的最少按键数。(就是一种技能的三个发球的排列总数为6)
转移就暴力枚举上一个技能的结尾状态,然后算一下有几个 法球是可以重复使用的,取个最优值就行了。
预处理一下第i种技能的排列为z1的时候转移到第j种技能状态为z2需要的步数数组dis
写一下全排列,然后多写函数结构化程序,实现也是较为简单的。
代码:
#define _CRT_SECURE_NO_WARNINGS #include<bits/stdc++.h> using namespace std; #define ll long long const int N = 2e5 + 10; int dis[10][10][6][6]; const int INF = 0x3f3f3f3f; ll dp[N][6]; int get_id(char ch) { if (ch == 'Y')return 0; if (ch == 'V')return 1; if (ch == 'G')return 2; if (ch == 'C')return 3; if (ch == 'X')return 4; if (ch == 'Z')return 5; if (ch == 'T')return 6; if (ch == 'F')return 7; if (ch == 'D')return 8; if (ch == 'B')return 9; } string str[10] = { "QQQ","QQW","QQE","WWW","QWW","WWE","EEE","QEE","WEE","QWE" }; string get_string(int id, int num) { string s = str[id]; string ans; int p[3] = { 0,1,2}; int cnt = 0; do { if (cnt++ == num) { //ans=str[id][0]+str[id][1] + str[id][2]; ans.push_back(str[id][p[0]]); ans.push_back(str[id][p[1]]); ans.push_back(str[id][p[2]]); return ans; } }while(next_permutation(p, p + 3)); } int get_val(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; } void init(){ string s1, s2; for(int i=0;i<10;i++) for (int j = 0; j < 10; j++) { for(int z1=0;z1<6;z1++) for (int z2 = 0; z2 < 6; z2++) { s1 = get_string(i, z1); s2 = get_string(j, z2); dis[i][j][z1][z2] = get_val(s1, s2); } } } char s[N]; int n; int main() { while (~scanf("%s", &s)) { //(hdu上面必须加多组输入) n = strlen(s); for (int i = 1; i < n; i++) for (int j = 0; j < 6; j++) dp[i][j] = INF; init(); for (int i = 0; i < 6; i++)dp[0][i] = 4; int id1, id2; for (int i = 1; i < n; i++) { id1 = get_id(s[i - 1]); id2 = get_id(s[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] + dis[id1][id2][k][j] + 1); } } ll ans = dp[n - 1][0]; for (int i = 1; i < 6; i++) { ans = min(ans, dp[n - 1][i]); } printf("%lld\n", ans); } return 0; }