UVALive 6430 Points(dp)

本文介绍了一种通过动态规划解决射击游戏目标选择问题的方法。玩家需选择射击目标以获得最大分数,依据相邻目标是否被选中,每个目标有不同的得分。文章详细解释了解题思路与算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

6430 Points
John is a fan of amusement parks. He goes every weekend and plays di erent games. This weekend he
found a challenging one | it is a target shooting game. The targets are placed along a straight line.
For all target positions i (assume the target numbering goes from right to left), there are three possible
points that John can win if he chooses that target: ai, if there are no neighbor targets chosen, bi if one
neighbor, and ci if two neighbors. Could you help John choose the targets in order to maximize the
number of points he can win?
Input
The input le contains several test cases, each of them as described below.
The program input starts with the number n (n < 1000000) of targets. Follows the values of ai, bi,
and ci for each target i.
The input data are correct and terminate with an end of le.
Output
For each test case, the program write to the output the maximum number of points John can win on
a line by itself.
The program prints the result to the standard output from the beginning of a line.
Hint: Input/output samples are in the table below. There are two tests. Each consists of only one
target.
For the rst one n = 1, a1 = 3, b1 = 0, c1 = 0, and the maximum number of points is 3. For the
second one n = 1, a1 = 1, b1 = 2, c1 = 3, and the maximum number of points is 1.The result consists
of the maximum number of points John can win, printed from the beginning of the line.
Sample Input
1
3 0 0
1
1 2 3
Sample Output
3

1


题意:n个靶子,现在要选一些靶子,使得得分最高。对于第i个靶子,如果它左右两边都没有靶子被选那么可以得到a(i)分,如果两边只有一边被选,可以得到b(i)分。如果两边的靶子都被选,得到c(i)分。


题解:开始的时候问题是:从1到n个靶子中选靶子,并且第1个的前一个靶子没有被选。

如果选了第1个靶子,那么问题变成了:从2到n的靶子中选靶子,并且第1个靶子的前一个靶子被选。

如果没有选第1个靶子,那么问题变成了:从2到n的靶子中选靶子,并且第1个靶子的前一个靶子没被选。

可以发现下面两个问题是第一个问题的子问题。

所以我们可以用dp[i][0,1]表示从i到n的靶子中选靶子,第1个靶子的前一个选或没选,能得到的最大分数。

但是转移的时候,为了计算选一个靶子的得分,我们还要记录一维状态表示第1个靶子选或者没选。

用dp[i][0,1][0,1]表示从i到n的靶子中选靶子,第1个靶子的前一个靶子选或者没选,第1个靶子选或者不选,该状态下的最大得分。

转移如下:

dp[i][0][0]=max(dp[i+1][0][0],dp[i+1][0][1]).

dp[i][1][0]=max(dp[i+1][0][0],dp[i+1][0][1]).

dp[i][0][1]=max(dp[i+1][1][0]+a[i],dp[i+1][1][1]+b[i]).

dp[i][1][1]=max(dp[i+1][1][0]+b[i],dp[i+1][1][1]+c[i]).

初始化:

dp[n][0,1][0]=0;

dp[n][0][1]=a[n];

dp[n][1][1]=b[n];

当这题还有其他的dp方法,如dp[i][j]表示前i个靶子已经处理了,第i-2,i-1,i个靶子选与没选的二进制状态为j,该状态能得到的最大分数。

代码如下:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<map>
#include<list>
#include<queue>
#include<string.h>
#define nn 1100000
#define inff 0x3fffffff
using namespace std;
typedef long long LL;
int a[nn],b[nn],c[nn];
LL  dp[nn][2][2];
int n;
int main()
{
    int i;
    while(scanf("%d",&n)!=EOF)
    {
        for(i=1;i<=n;i++)
        {
            scanf("%d%d%d",&a[i],&b[i],&c[i]);
        }
        dp[n][0][0]=dp[n][1][0]=0;
        dp[n][1][1]=b[n];
        dp[n][0][1]=a[n];
        for(i=n-1;i>=1;i--)
        {
            dp[i][0][0]=max(dp[i+1][0][0],dp[i+1][0][1]);
            dp[i][1][0]=max(dp[i+1][1][0],dp[i+1][1][1]);
            dp[i][0][1]=max(dp[i+1][1][0]+a[i],dp[i+1][1][1]+b[i]);
            dp[i][1][1]=max(dp[i+1][1][0]+b[i],dp[i+1][1][1]+c[i]);
        }
        printf("%lld\n",max(dp[1][0][1],dp[1][0][0]));
    }
    return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值