Invoker HDU - 6739

题意:

对于我这种不玩游戏的人来说,理解题目大意花了好久的时间。
以下题目大意引用自此博客

在 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 表示,便可获得当前法球组合所对应的技能,同时原有的三个法球也不会消失,先后顺序的状态也不会改变。
现在给定一个技能序列,你想按照给定的顺序将他们一个一个地祈唤出来,同时你想用最少的按键来达到目标,所以你想知道对于给定的一个技能序列,最少按多少次键才能把他们都祈唤出来。
注意:游戏开始的时候,祈求者是没有任何法球的。

分析:

首先确定状态,因为序列是无序的,所以对于要产生的一个字符,有6种对应的组合(假设所有的字符均不相同)。
\(dp[i][j]\):表示产生序列中第 \(i\) 个位置的字符对应的第 \(j\) 中序列所需的操作数。
状态转移方程:\(dp[i][j]=min(dp[i][j],dp[i-1][k]+cal(ss[i],ss[i-1],j,k)+1);\)
其中 \(cal()\),表示通过对比产生第 \(i\)\(i-1\) 位置的字符对应的第 \(j\) 和 第 \(k\) 种序列的差别,来确定操作的次数。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
const int inf=0x3f3f3f3f;
char ss[N];
int dp[N][7],p[6][3]={0,1,2,0,2,1,1,0,2,1,2,0,2,1,0,2,0,1};//序列位置的排列方式
map<char,string>mp;
void init()
{
    mp['Y']="QQQ";
    mp['V']="QQW";
    mp['G']="QQE";
    mp['C']="WWW";
    mp['X']="QWW";
    mp['Z']="WWE";
    mp['T']="EEE";
    mp['F']="QEE";
    mp['D']="WEE";
    mp['B']="QWE";
}
int cal(char c1,char c2,int x,int y)
{//注意比较的位置
    string s=mp[c1];
    string t=mp[c2];
    if(s[p[x][0]]==t[p[y][0]]&&s[p[x][1]]==t[p[y][1]]&&s[p[x][2]]==t[p[y][2]])
        return 0;
    else if(s[p[x][0]]==t[p[y][1]]&&s[p[x][1]]==t[p[y][2]])
        return 1;
    else if(s[p[x][0]]==t[p[y][2]])
        return 2;
    else return 3;
}
int main()
{
    init();
    while(scanf("%s",ss+1)!=EOF)
    {
        int len=strlen(ss+1);
        memset(dp,inf,sizeof(dp));
        for(int i=0;i<6;i++) dp[1][i]=4;
        for(int i=2;i<=len;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(ss[i],ss[i-1],j,k)+1);
            }
        }
        int ans=inf;
        for(int i=0;i<6;i++)
            ans=min(ans,dp[len][i]);
        printf("%d\n",ans);
    }
    return 0;
}

posted @ 2020-05-30 11:45  xzx9  阅读(284)  评论(0编辑  收藏  举报