2019CCPC秦皇岛 I Invoker

题意:

就是魔法召唤技能,最少的符号数之类的。

思路:

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

 

转载于:https://www.cnblogs.com/gzr2018/p/11605385.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值