CF358D Dima and Hares

CF358D Dima and Hares

洛谷评测传送门

题目描述

Dima liked the present he got from Inna very much. He liked the present he got from Seryozha even more.

Dima felt so grateful to Inna about the present that he decided to buy her nn hares. Inna was very happy. She lined up the hares in a row, numbered them from 1 to nn from left to right and started feeding them with carrots. Inna was determined to feed each hare exactly once. But in what order should she feed them?

Inna noticed that each hare radiates joy when she feeds it. And the joy of the specific hare depends on whether Inna fed its adjacent hares before feeding it. Inna knows how much joy a hare radiates if it eats when either both of his adjacent hares are hungry, or one of the adjacent hares is full (that is, has been fed), or both of the adjacent hares are full. Please note that hares number 1 and nn don't have a left and a right-adjacent hare correspondingly, so they can never have two full adjacent hares.

Help Inna maximize the total joy the hares radiate. :)

输入格式

The first line of the input contains integer nn (1<=n<=3000)(1<=n<=3000) — the number of hares. Then three lines follow, each line has nn integers. The first line contains integers a_{1}a1 a_{2}a2 ...... a_{n}*a**n* . The second line contains b_{1},b_{2},...,b_{n}b1,b2,...,*b**n* . The third line contains c_{1},c_{2},...,c_{n}c1,c2,...,*c**n* . The following limits are fulfilled: 0<=a_{i},b_{i},c_{i}<=10^{5}0<=ai,bi,*c**i*<=105 .

Number a_{i}*a**i* in the first line shows the joy that hare number ii gets if his adjacent hares are both hungry. Number b_{i}*b**i* in the second line shows the joy that hare number ii radiates if he has exactly one full adjacent hare. Number с_{i} in the third line shows the joy that hare number ii radiates if both his adjacent hares are full.

输出格式

In a single line, print the maximum possible total joy of the hares Inna can get by feeding them.

题意翻译

N个物品排成一排,按照一定顺序将所有物品都拿走,如果拿走某个物品时相邻两个物品都没有被拿过,那么得到的价值为ai;如果相邻的两个物品有一个被拿过(左右无所谓),那么得到的价值为bi;如果相邻的两个物品都被拿走了,那么对应价值为ci。问能够获得的最高价值为多少。

输入输出样例

输入 #1复制

输出 #1复制

输入 #2复制

输出 #2复制

输入 #3复制

输出 #3复制

题解:

(2019.10.21模拟赛爆蛋场)

一道非常好的DP。

我给它起了个名字:双重DP

我们在初步分析题意的基础上,可以发现,这个物品的选择与否与左右两个物品有关系。

也就是说,针对于每个物品,决策不仅有选和不选两种,而且和选择的顺序有关系。

对于这种问题,我们采用这种办法:

开两重DP数组,其中\(dp[i] [0]\)表示前\(i-1\)件物品在先留下\(i-1\)这件物品的最大价值。

同理:\(dp[i] [1]\)表示前\(i-1\)件物品在取走\(i-1\)这件物品的最大价值。

那么我们设计出了以下的动态转移方程:
\[ dp[i][0]=max(dp[i-1][0]+b[i-1],dp[i-1][1]+c[i-1]); \]

\[ dp[i][1]=max(dp[i-1][0]+a[i-1],dp[i-1][1]+b[i-1]); \]

我们着重解释这个状态转移方程:

(先上张图)

现在,我们对\(i\)件物品进行决策,我们分别对其进行两重\(DP\)。那么,第一个状态转移方程(关于\(dp[i][0]\)的)种涉及到了\(dp[i-1][0/1]\),根据我们对状态的定义。这个\(dp[i-1][0/1]\)涉及到了第\(i-2\)件物品,那么,我们就恍然大悟了:为什么我们状态定义的是前\(i-1\)件物品的最大价值?因为虽然方程设置的是\(dp[i]\),但我们其实是在对\(i-1\)这个点进行状态上的决策。

在第一个状态转移方程中,实际上max()函数中的两个分量的第一个分量就是表示:取走物品顺序为:\(i\to i-1\to i-2\),易知,此时的\(i-1\)物品对答案的贡献价值应该是\(b[i-1]\)(因为\(i\)被取走了,而\(i-2\)仍然留着)。同理,第二个分量的意义就是:取走物品顺序为:\(i-2\to i\to i-1\) ,而答案就应该加上\(c[i-1]\)

第二个状态转移方程同理。

最后在统计答案的时候,一定要记住,你的状态定义的是前\(i-1\)个物品的价值,并没有把最后的物品加上。所以我们输出的时候其实还要进行一次决策。

总结:

\(DP\)算法的重要性在算法竞赛中不言而喻。而弄明白各种\(DP\)题型的状态和转移方程设计技巧更是重中之重。对于每一道\(DP\)题目,都要好好想一想自己在这道题目中学到了什么。对于这道题,我们可以从中学习到对于多种状态决策的\(DP\)的设计方式。并结合图例发现了\(DP\)决策过程中,物品选择顺序在状态转移方程中的体现。我想,能获得这些收获,这道题的意义才不仅仅是一个虚弱无力的\(AC\)吧。

代码:

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=3005;
char *p1,*p2,buf[100000];
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int read()
{
    int x=0,f=1;
    char ch=nc();
    while(ch<48){if(ch=='-')f=-1;ch=nc();}
    while(ch>47)    x=(((x<<2)+x)<<1)+ch-48,ch=nc();
    return x*f;
}
int n;
int a[maxn],b[maxn],c[maxn];
int dp[maxn][3];
//dp[i][0]表示前i-1的价值(先留下i-1)
//dp[i][1]表示前i-1的价值(先取走i-1)
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    for(int i=1;i<=n;i++)
        b[i]=read();
    for(int i=1;i<=n;i++)
        c[i]=read();
    if(n==1)
    {
        printf("%d",a[1]);
        return 0;
    }
    dp[2][0]=b[1];
    dp[2][1]=a[1];
    for(int i=3;i<=n;i++)
    {
        dp[i][0]=max(dp[i-1][0]+b[i-1],dp[i-1][1]+c[i-1]);
        dp[i][1]=max(dp[i-1][0]+a[i-1],dp[i-1][1]+b[i-1]);
    }
    printf("%d",max(dp[n][0]+a[n],dp[n][1]+b[n]));
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/fusiwei/p/11715530.html