POJ 4150 上机(dp)

上机

总时间限制:1000ms

内存限制:65536kB

描述

又到周末了,同学们陆陆续续开开心心的来到机房上机。jbr也不例外,但是他到的有点晚,发现有些机位上已经有同学正在做题,有些机位还空着。细心的jbr发现,一位同学来到机房,坐在机位i上,如果他的左右两边都空着,他将获得能力值a[i];如果当他坐下时,左边或者右边已经有一个人在上机了,他将获得能力值b[i];如果当他坐下时,他的左边右边都有人在上机,他将获得能力值c[i]。

同时他发现,已经在上机的同学不会受到刚要坐下的同学的影响,即他们的能力值只会在坐下时产生,以后不会发生变化;第一个机位左边没有机位,最后一个机位右边没有机位,无论何时坐在这两个机位上将无法获得c值。

这时jbr发现有一排机器还空着,一共有N个机位,编号1到N。这时有N位同学们陆陆续续来到机房,一个一个按照顺序坐在这排机位上。聪明的jbr想知道怎么安排座位的顺序,可以使这N位同学获得能力值的和最大呢?

输入

第一行一个整数N(1<= N <= 10000)

第二行N个数,表示a[i]

第三行N个数,表示b[i]

第四行N个数,表示c[i]

(1<= a[i],b[i],c[i] <=10000)

输出

一个整数,表示获得最大的能力值和

样例输入

扫描二维码关注公众号,回复: 2730430 查看本文章
4
1 2 2 4
4 3 3 1
2 1 1 2

样例输出

14

提示

第一位同学坐在第四个机位上,获得能力值4;
第二位同学坐在第三个机位上,获得能力值3;
第三位同学坐在第二个机位上,获得能力值3;
第四位同学坐在第一个机位上,获得能力值4;
总和为14。

Analysis:

这个题目看起来很复杂,看起来有两方面问题:一个是学生选哪个座位,另一个是学生坐下的次序不同,得到的分数也不同。

然而,事实上每个学生是没有差别的,最后也一定会把座位坐满,所以学生选哪个座位不是问题要考虑的,也就是说我们问题的中心并不在于学生上,而是在座位上,问题在于每个座位是以怎样的方式坐下去的

事实上,一个位置的坐下状态和它周围的位置坐下状态互相影响,比如若位置i坐下时,右边没人,那么位置i+1坐下时左边就一定有人,这就是状态转移了,由此可以想到用动态规划去做。

用dp[i][0]表示第i个座位的人坐下时左右无人,dp[i][1]表示第i个座位的人坐下时左边有人而右边无人,dp[i][2]表示第i个座位的人坐下时右边有人而左边无人,dp[i][3]表示第i个座位坐下时左右都有人。然后我们就可以递推求解。举例如下:

可以用dp[i][0]去更新dp[i+1][1]和dp[i+1][3], 因为若在i这个位置坐下时左右无人的话(dp[i][0])那么第i+1个位置坐下时必定左边有人(dp[i+1][1]或dp[i+1][3]),这就像是我们在上一段看到的intuition一样。具体来说就是,

        dp[i+1][1]=max(dp[i+1][1],dp[i][0]+b[i+1])  (用dp[i][0]更新dp[i+1][1])
        dp[i+1][3]=max(dp[i+1][3],dp[i][0]+c[i+1])  (用dp[i][0]更新dp[i+1][3])   其他依次类推。

由以上的分析我们可以知道,用刷表法写程序可以很自然地得到最后的解max(dp[n-1][0],dp[n-1][1]);

代码如下:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<sstream>
#include<cmath>
#include<iterator>
#include<bitset>
#include<stdio.h>
#include<time.h>
using namespace std;
#define _for(i,a,b) for(int i=(a);i<(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
typedef long long LL;
const int INF = 0xffffff0;
const int MOD = 1e9+7;
const int maxn =10005;

int n,dp[maxn][4];//在第i座位的人坐下时,左右都无人(0),左有人(1),右有人(2),左右都有人(3)
int a[maxn],b[maxn],c[maxn];

int main() {
   //freopen("C:\\Users\\admin\\Desktop\\in.txt", "r", stdin);
   //freopen("C:\\Users\\admin\\Desktop\\out.txt", "w", stdout);
    scanf("%d",&n);
    for(int i=0;i<n;++i)
        scanf("%d",&a[i]);
    for(int i=0;i<n;++i)
        scanf("%d",&b[i]);
    for(int i=0;i<n;++i)
        scanf("%d",&c[i]);

    dp[0][0]=a[0];
    dp[0][1]=-INF;
    dp[0][2]=b[0];
    dp[0][3]=-INF;
    for(int i=0;i+1<n;++i){
        dp[i+1][1]=max(dp[i+1][1],dp[i][0]+b[i+1]);
        dp[i+1][3]=max(dp[i+1][3],dp[i][0]+c[i+1]);
        dp[i+1][1]=max(dp[i+1][1],dp[i][1]+b[i+1]);
        dp[i+1][3]=max(dp[i+1][3],dp[i][1]+c[i+1]);
        dp[i+1][0]=max(dp[i+1][0],dp[i][2]+a[i+1]);
        dp[i+1][2]=max(dp[i+1][2],dp[i][2]+b[i+1]);
        dp[i+1][0]=max(dp[i+1][0],dp[i][3]+a[i+1]);
        dp[i+1][2]=max(dp[i+1][2],dp[i][3]+b[i+1]);
    }
    printf("%d\n",max(dp[n-1][0],dp[n-1][1]));

    return 0;
}

猜你喜欢

转载自blog.csdn.net/tomandjake_/article/details/81270734