分享一道有趣的题
LGTB 玩THD
LGTB 最近在玩一个类似DOTA 的游戏名叫THD有一天他在守一座塔,对面的N 个小兵排成一列从近到远站在塔前面每个小兵有一定的血量hi,杀死后有一定的金钱gi每一秒,他都可以攻击任意一个活着的小兵,对其造成P 点伤害,如果小兵的血量低于1 点,小兵死亡,他得到金钱。他也可以不攻击任何小兵。每一秒LGTB 攻击完毕之后,塔会攻击距离塔最近的一个活着的小兵,对其造成Q 点伤害,如果小兵的血量低于1 点,小兵死亡,LGTB 不会得到金钱现在LGTB 想知道,在他选择最优策略时,他能得到多少钱。
输入
输入第一行包含3 个整数P, Q, N接下来N 行,每行包含2 个整数hi, gi第i 个小兵和塔之间的距离为i输入的意义如题面所示
对于20% 的数据,1< N< 4
对于50% 的数据,1< N< 20
对于100% 的数据,20< P,Q< 200, 1< N< 100, 1< hi< 200, 0< gi< 106输出
输出包含一个整数W,代表LGTB 最多能获得的金钱
样例输入
20 60
380 100
80 200
120 300样例输出
500
这道题一来就很崩溃,补兵按感觉补就行了为什么还要来写程序。。。算了,先不说这些,这道题一看就先想到dfs,但也一看就过不了,再一看可以看出很明显是dp,我写的和std不一样但还是可以A。
**我们可以认为,每一秒,我可以A兵,也可以把这一秒存起来,后面再用,这样就可以后面一秒5刀,6刀。我管这个现在一秒可以A几刀叫体力值k;我们还建立一个数组a,表示要额外消费多少点体力值可以补到刀,及a[i]=(塔最大攻击次数-人最小攻击次数)
再建立一个数组v,表示不A这个兵它最多抗几下。这时我们就可以开始dp了。设f[i][j][k]表示前i个兵,补j个刀,剩余体力值为k的最大获得金钱。**
f[i][j][k]=max(不补这个兵的最大钱,补这个兵的最大钱)
f[i][j][k]=max(f[i-1][j][k-v[i]],f[i-1][j-1][k+a[i]]+g[i])
大概就是这样,下面是代码,可以参考。
#include<cstdio>
#include<cstring>
#define M 101
using namespace std;
int P,Q,n,h[M],g[M],aa[2*M],vv[2*M],a[M],v[M],f[M][M][10*M],m;
int main()
{
freopen("thd.in","r",stdin);
freopen("thd.out","w",stdout);
cin>>P>>Q>>n;
for(int i=1;i<=n;i++)
scanf("%d%d",&h[i],&g[i]);
for(int i=1;i<=P;i++)
aa[i]=1;
for(int i=P+1;i<=Q;i++)
aa[i]=(i-P-1)/P+2;
for(int i=Q+1;i<=200;i++)
aa[i]=aa[i-Q]-1;
for(int i=1;i<=200;i++)
vv[i]=(i-1)/Q+1;
for(int i=1;i<=n;i++)
{
a[i]=aa[h[i]];//求a与v
v[i]=vv[h[i]];
m+=v[i];
}
if(n==1&&a[1]==1)
{
cout<<g[1];
return 0;
}
m+=2;
memset(f,-63,sizeof(f));//初始化为大负值
int v_sum=0;
for(int i=1;i<=n;i++)
{
v_sum+=v[i];
f[i][0][v_sum+1]=0;//初始化不补兵的情况
}
if(a[1]<=1)
f[1][1][-a[1]+1]=g[1];
for(int i=2;i<=n;i++)
for(int j=1;j<=i;j++)
for(int k=0;k<=m;k++)
if(k-v[i]>=0&&i-1>=j)
f[i][j][k]=max(f[i-1][j][k-v[i]],f[i-1][j-1][k+a[i]]+g[i]);
else f[i][j][k]=f[i-1][j-1][k+a[i]]+g[i];
int i=n,mx=0;
for(int j=1;j<=i;j++)
for(int k=0;k<=m;k++)
{
mx=max(mx,f[i][j][k]);
}
cout<<mx;
return 0;
}
大概就这样,如果有什么问题,或错误,请在评论区提出,谢谢。