南阳理工学院第三届省内高校新生程序设计大赛(决赛)-Problem B. 博弈论的实践学习

解题思路:

动态规划,做动态规划题时有两大核心其一我们要用一些状态去表示所有的集合(不重不漏)其二我们表示的这些状态都要能正确的转化过来估计这两大核心大家都应该很熟悉,就是很难做到 别急经过题目的数量和时间的沉淀大家肯定会弄明白的。

f[i][j][k] 表示前i招且第i招使用的技能为j且连用了k次所获得的最大伤害,题目说了总共有3中技能且最多连用2次连招,所以公用6种状态(有点多)分别是f[i][0][1],f[i][0][2],f[i][1][1],f[i][1][2],f[i][2][1],f[i][2][2]; 如何把这六种状态表示出来呢分f[i][j][k]肯定f[i-][j0][k0]转化过来的,f[i][0][2]是从分f[i-1][0][1]转化过来的,f[i][0][1]是从f[i-1][j][k](j=1,2,k=1,2)转化过来的后面四种状态类似前两种状态,显然答案是max(f[n][j][k]),时间复杂度为6n,废话不多说看代码吧,不过写的很乱

代码

#include<iostream>
#define int long long
using namespace std;
const int N=2e5+5;
char s[N];
int f[N][3][3];
signed main()
{
	int n,a,b,c,d;
	cin>>n>>a>>b>>c>>d;
	cin>>s+1;
	//把三种技能转化成数字表示
	for(int i=1;i<=n;i++)
	{
		if(s[i]=='A')
		s[i]='0';
		if(s[i]=='B')
		s[i]='1';
		if(s[i]=='G')
		s[i]='2';
	}
	for(int i=1;i<=n;i++)
	{  
		if(s[i]=='0')
		{
          //把六种状态全部正确转化出来
		   for(int j=1;j<=2;j++)
		   for(int k=1;k<=2;k++)
		   f[i][0][1]=max(f[i][0][1],f[i-1][j][k]+d);
		  f[i][0][2]=max(f[i][0][2],f[i-1][0][1]+d);
		  for(int j=0;j<=2;j++)
		  {
		  	for(int k=1;k<=2;k++)
		  	{
		  		 if(j==1)
		  		 continue;
		  		 f[i][1][1]=max(f[i][1][1],f[i-1][j][k]+a);
			  }
		  }
		  f[i][1][2]=max(f[i][1][2],f[i-1][1][1]+a);
		  for(int j=0;j<2;j++)
		  for(int k=1;k<=2;k++)
		  f[i][2][1]=max(f[i][2][1],f[i-1][j][k]);
		  f[i][2][2]=max(f[i][2][2],f[i-1][2][1]);
		}
		if(s[i]=='1')
		{     //把六种状态全部正确转化出来
			for(int j=0;j<=2;j++)
		  {
		  	for(int k=1;k<=2;k++)
		  	{
		  		 if(j==1)
		  		 continue;
		  		 f[i][1][1]=max(f[i][1][1],f[i-1][j][k]+d);
			  }
		  }
		    f[i][1][2]=max( f[i][1][2],f[i-1][1][1]+d);
		    for(int j=0;j<2;j++)
		    {
		    	for(int k=1;k<=2;k++)
		    	f[i][2][1]=max(f[i][2][1],f[i-1][j][k]+c);
			}
			f[i][2][2]=max(f[i][2][2],f[i-1][2][1]+c);
			  for(int j=1;j<=2;j++)
		   for(int k=1;k<=2;k++)
		   f[i][0][1]=max(f[i][0][1],f[i-1][j][k]);
		  f[i][0][2]=max(f[i][0][2],f[i-1][0][1]);
		}
		if(s[i]=='2')
		{   //把六种状态全部正确转化出来
			for(int j=1;j<=2;j++)
			for(int k=1;k<=2;k++)
			f[i][0][1]=max(f[i][0][1],f[i-1][j][k]+b);
			f[i][0][2]=max(f[i][0][2],f[i-1][0][1]+b);
			 for(int j=0;j<=2;j++)
		  {
		  	for(int k=1;k<=2;k++)
		  	{
		  		 if(j==1)
		  		 continue;
		  		 f[i][1][1]=max(f[i][1][1],f[i-1][j][k]);
			  }
		  }
		  f[i][1][2]=max(f[i][1][2],f[i-1][1][1]);
		  for(int j=0;j<2;j++)
		    {
		    	for(int k=1;k<=2;k++)
		    	f[i][2][1]=max(f[i][2][1],f[i-1][j][k]);
			}
			f[i][2][2]=max(f[i][2][2],f[i-1][2][1]);
			
		}
	}
	int ans=0;
	for(int j=0;j<=2;j++)
	for(int k=1;k<=2;k++)
	ans=max(ans,f[n][j][k]);
	cout<<ans<<endl;
	return 0;
}

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值