[HDOJ6739]Invoker

原题来自icpc2019秦皇岛
hdoj上的重现赛
数据有坑,题面说明是单组数据但实际是多组数据
辣鸡hdoj改数据不改题面

Problem Description
In dota2, there is a hero named Invoker. He has 3 basic skills in the game, which are Quas, Wex and Exort. Once he launches a basic skill, he will gain the corresponding element, where Quas gives “Q”, Wex gives “W” and Exort gives “E”.
Invoker can’t have more than 3 elements simultaneously. If he launches a basic skill when he already owns 3 elements, he will get the corresponding element and lose the element he gained the earliest.
As can be seen, there are 10 unordered combinations of 3 elements in 3 types, each represents a special skill, which are as follows:

  • Cold Snap: unordered element combination “QQQ”, denoted by “Y”
  • Ghost Walk: unordered element combination “QQW”, denoted by “V”
  • Ice Wall: unordered element combination “QQE”, denoted by “G”
  • EMP: unordered element combination “WWW”, denoted by “C”
  • Tornado: unordered element combination “QWW”, denoted by “X”
  • Alacrity: unordered element combination “WWE”, denoted by “Z”
  • Sun Strike: unordered element combination “EEE”, denoted by “T”
  • Forge Spirit: unordered element combination “QEE”, denoted by “F”
  • Chaos Meteor: unordered element combination “WEE”, denoted by “D”
  • Deafening Blast: unordered element combination “QWE”, denoted by “B”

When Invoker owns 3 elements, he can launch the invoking skill, denoted by “R”, to gain the special skill according to the elements he currently owns. After invoking, the elements won’t disappear, and the chronological order of the 3 elements won’t change.
Now given a sequence of special skills, you want to invoke them one by one with using the minimum number of basic skills(Q,W,E) and invoking skill®. Print the minimum number in a single line.
At the beginning, Invoker owns no elements. And you should re-invoke the special skills even if you have already invoked the same skills just now.

Input
Input a single line containing a string s (1 ≤ |s| ≤ 100 000) that only contains uppercase letters in {B, C, D, F, G, T, V, X, Y, Z}, denoting the sequence of special skills.

Output
Output a single line containing a positive integer, denoting the minimum number of skills to launch.

题意
Dota2背景,说的是英雄搓技能(误?)最后输入的3个Q、W、E键中Q、W、E键数量的不同组合(10种)各对应一个技能,按R来施放这个对应技能,问按给定技能序列施放对应技能的最少按键次数是多少。(即使相邻技能相同也要各按一次R来施放)

思路
显然QWE的组合只有 3 3 3^3 33种组合,而这些组合分别对应不同的Q、W、E键数量的组合,所以我们可以用0~26来记录每种组合(3进制)打个表来计算从任何一个组合转移到另一个组合所需的按键数(显然,包括R)
设这个记录数组为 t r e c [ ] [ ] trec[][] trec[][]
t r e c [ i ] [ j ] trec[i][j] trec[i][j]表示从组合 i i i到组合 j j j的按键数
那么可得状态转移方程 d p [ i + 1 ] [ j ] = m i n ( d p [ i ] [ k ] + t r e c [ k ] ) dp[i+1][j]=min(dp[i][k]+trec[k]) dp[i+1][j]=min(dp[i][k]+trec[k])其中 j j j属于所有第 i + 1 i+1 i+1个组合对应的值的集合, k k k属于所有第 i i i个组合对应的值的集合。最后找到 d p [ n ] [ i ] dp[n][i] dp[n][i]中的最小值就可以了, i i i属于所有第 n n n个组合对应的值的集合。

AC代码(丑)

#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
vector<int>mov[20];
int trec[50][50];
int ct[5];
int pz[500];
char s[100005];
int dp[100005][30];
int n;
int main()
{
	//0=Q,1=W,2=R
	for(int h1=0;h1<3;h1++)
	for(int h2=0;h2<3;h2++)
	for(int h3=0;h3<3;h3++)
	for(int t1=0;t1<3;t1++)
	for(int t2=0;t2<3;t2++)
	for(int t3=0;t3<3;t3++)
	{
		int a_=h1*9+h2*3+h3,b_=t1*9+t2*3+t3;
		trec[a_][b_]=4;
		if(h3==t3&&h2==t2&&h1==t1)trec[a_][b_]=1;else
		if(h3==t2&&h2==t1)trec[a_][b_]=2;else
		if(h3==t1)trec[a_][b_]=3;
	}//此处计算不同组合之间的按键次数
	for(int h1=0;h1<3;h1++)
	{
		ct[h1]++;
		for(int h2=0;h2<3;h2++)
		{
			ct[h2]++;
			for(int h3=0;h3<3;h3++)
			{
				ct[h3]++;
				if(ct[0]==3) mov[0].push_back(h1*9+h2*3+h3);
				else if(ct[0]==2&&ct[1]==1)mov[1].push_back(h1*9+h2*3+h3);
				else if(ct[0]==2&&ct[2]==1)mov[2].push_back(h1*9+h2*3+h3);
				else if(ct[1]==3) mov[3].push_back(h1*9+h2*3+h3);
				else if(ct[1]==2&&ct[0]==1)mov[4].push_back(h1*9+h2*3+h3);
				else if(ct[1]==2&&ct[2]==1)mov[5].push_back(h1*9+h2*3+h3);
				else if(ct[2]==3) mov[6].push_back(h1*9+h2*3+h3);
				else if(ct[2]==2&&ct[0]==1)mov[7].push_back(h1*9+h2*3+h3);
				else if(ct[2]==2&&ct[1]==1)mov[8].push_back(h1*9+h2*3+h3);
				else mov[9].push_back(h1*9+h2*3+h3);
				ct[h3]--;
			}
			ct[h2]--;
		}
		ct[h1]--;
	}//此处记录每个组合对应哪个技能,push到对应的vector中
	pz['B']=9;pz['D']=8;pz['F']=7;pz['T']=6;pz['Z']=5;
	pz['X']=4;pz['C']=3;pz['G']=2;pz['V']=1;pz['Y']=0;
	//此处记录每个字母对应的技能编号(人蠢不会用map)
	while(scanf("%s",s)!=EOF)
	{
		for(n=0;s[n];n++);
		int temp=mov[pz[s[0]]].size();
		for(int i=0;i<temp;i++)dp[0][mov[pz[s[0]]][i]]=4;
		for(int i=1;i<n;i++)
		{
			int temp2=mov[pz[s[i]]].size();
			temp=mov[pz[s[i-1]]].size();
			for(int j=0;j<temp2;j++) 
			dp[i][mov[pz[s[i]]][j]]=dp[i-1][mov[pz[s[i-1]]][0]]+trec[mov[pz[s[i-1]]][0]][mov[pz[s[i]]][j]];
			for(int k=1;k<temp;k++)
			for(int j=0;j<temp2;j++) 
			dp[i][mov[pz[s[i]]][j]]=min(dp[i-1][mov[pz[s[i-1]]][k]]+trec[mov[pz[s[i-1]]][k]][mov[pz[s[i]]][j]],dp[i][mov[pz[s[i]]][j]]);
		}
		int ans=1e9;
		temp=mov[pz[s[n-1]]].size();
		for(int i=0;i<temp;i++)ans=min(ans,dp[n-1][mov[pz[s[n-1]]][i]]);
		printf("%d\n",ans);		
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值