NOJ1859 越野赛 三维DP

题目描述

大戈壁越野赛前后分为很多赛段,一个车队也有多辆车。一个车队在一个赛段只能使用一辆车,但是到达赛段中转站(分隔各赛段的点)时可以任意更换车辆,当然也可以不换。在不同赛段,不同的车有着不同的表现,如果规则不限定换车次数,显然可以在每一个赛段都用最好用的车,但很不幸,换车次数有限定,那么,安排一个合理的换车策略十分重要。我们认为,车队可以选择任意一种车开始赛程,不算换车次数。

现在依次给出从起点到终点N个赛段中每辆车的表现(跑完当前赛段所需时间),请计算出跑完全部赛程所需最短时间

输入

第一行包含三个正整数N、M、Q,分别表示赛段数、车队用车种类、最大更换车辆次数限制(1≤N≤10000,1≤M≤10,1≤Q≤100)。

接下来M行,每行N个正整数。第i行第j个数表示i号车在第j赛段的表现(这辆车跑完这个赛段所需时间),每个赛段的时间上限保证不超过1000。

输出

输出一行,包含一个整数,表示车队在规则限定内的赛程最短完成时间

输入样例

3 2 1

1 4 1

2 2 3

输出样例

5

解题思路

三维DP  dp[i][j][k]数组表示到i段赛道,换了j次车,最后选择的车是k车的最小时间

假设我们现在已经考虑过前(i-1)段赛道  现在考虑第i段赛道。

如果在第i段赛道不换车 那么d[i][j][k] = d[i-1][j][k] + speed[i][k];

如果在第i段赛道换车 那么d[i][j][k] = min(d[i-1][j-1][x]) + speed[i][k]; (x不等于k)

把两个式子合在一起 则 d[i][j][k] = min(d[i-1][j][k] , d[i-1][j-1][x](x不等于k)) + speed[i][k]

最后的答案应该是min(d[赛道数][x][y])

下面考虑一下初始化........

可以看出(i,j)状态是由(i-1,j)和(i-1,j-1)这两个状态推出的 所以外循环遍历i 内循环遍历j 再在里面遍历k.

所以我们要初始化i = 1 和 j = 0的情况.....

详见代码

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define INF 1000000010
const int max_saidao = 10010;
const int max_che = 15;
const int max_huanche = 105;
using namespace std;
int speed[max_saidao][max_che];//speed[i][j]表示第i个赛道 第j辆车的速度
int dp[max_saidao][max_huanche][max_che];//dp[i][j][k]表示前i个赛道换了j次 最后使用的车是k  的最短时间
int main()
{
    int saidao,che,huanche;
    scanf("%d%d%d",&saidao,&che,&huanche);
    for(int i = 1 ; i <= che ; i ++) {
        for(int j = 1 ; j <= saidao ; j ++) scanf("%d",&speed[j][i]);
    }
    for(int i = 0 ; i <= saidao ; i ++) {
        for(int j = 0 ; j <= huanche ; j ++) {
            for(int k = 0 ; k <= che ; k ++) dp[i][j][k] = INF;
        }
    }
    //初始化dp[1][0][x]
    for(int i = 1 ;i <= che ; i ++) dp[1][0][i] = speed[1][i];
    //初始化dp[x][0][x]
    for(int i = 1 ;i <= che ; i ++) {//第i辆车,不换
        for(int j = 2 ; j <= saidao ; j ++) {
            dp[j][0][i] = dp[j-1][0][i] + speed[j][i];
        }
    }

    //dp
    for(int i = 2 ; i <= saidao ; i ++) {
        for(int j = 1 ; j <= huanche && j < i ; j ++) {
            for(int k = 1 ; k <= che ; k ++) {
                int _min = INF;
                for(int p = 1 ; p <= che ; p ++) {
                    if(p != k) if(_min > dp[i-1][j-1][p]) _min = dp[i-1][j-1][p];
                }
                if(_min > dp[i-1][j][k]) _min = dp[i-1][j][k];
                dp[i][j][k] = _min + speed[i][k];
            }
        }
    }

    //输出dp[saidao][x][y]中最小的
    int _min = INF;
    for(int i = 0 ; i <= huanche ; i ++) {
        for(int j = 1 ; j <= che ; j ++) {
            if(_min > dp[saidao][i][j]) _min = dp[saidao][i][j];
        }
    }
    printf("%d\n",_min);
    return 0;
}
时间: 2024-08-11 07:12:21

NOJ1859 越野赛 三维DP的相关文章

HDU 4433 locker(三维dp)

这题不太好想啊....我以为是记忆化搜索但是感觉最后的状态不好转移啊.别人都是用三维dp写的,感觉很巧啊. binshen写的:http://www.cnblogs.com/kuangbin/archive/2012/10/27/2742672.html 这题的意思就相当于是一个数字密码锁. 每次可以正向或者反向旋转连续的1-3个数字.求从现在状态转到目标状态需要的最少步数. 题目给了两个长度一样的由0-9组成的字符串.就相当于每次操作可以选择连续的1-3个数字加1或者减1.这不过这个加和减是循

!CodeForces 543A Writing Code --DP--(三维dp,滚动数组)

题意:n个程序员一起写m行代码,第i个程序员每写一行有a[i]个bug,求总bug不超过b的分配方案有多少种 分析:这题很像完全背包,不过求的不是最大/最小bug数,求的是bug数小于上限的分配方案.所以这题要用三维dp dp[i][j][k]表示前i个个程序员总共写了j行代码产生了k个bug时的plan数,这题有两种转移:1)第i个程序员再写一行:2)换第i+1号程序员写 所以方程:dp[i][j][k]=dp[i-1][j][k]+dp[i][j-1][k-a[i]],注意:程序员可能一行都

# codeforces 1272 F. Two Bracket Sequences(三维dp + bfs)

codeforces 1272 F. Two Bracket Sequences(三维dp + bfs) 题目大意 输入两个括号序列 s,t(不一定合法),你需要构造一个尽可能短的合法括号序列使得s,t 都是这个序列的子序列(子序列意味着不用连续) 解题思路 dp[i][j][k]表示匹配到s的第i个字符,匹配到t的第j个字符,并且此时(的个数比)多k个的时候的最小合法序列长度,k的上限是200(s和t中最多200个(或者)). 状态转移: 枚举答案合法序列的每一位是放置(或者) ? 放置(,如

CODEVS 1997 守卫者的挑战(三维dp)

题目很简单,就是一个三维的dp,状态转移方程很好想出来,有一点需要注意这道题目在取的中间过程的时候允许出现背包装不下的情况,只要最后的状态是可以的就行了.注意负数的转移就行了啊. maxn = 210 MLE, 201就AC了啊. 题目描述 Description 打开了黑魔法师Vani的大门,队员们在迷宫般的路上漫无目的地搜寻着关押applepi的监狱的所在地.突然,眼前一道亮光闪过."我,Nizem,是黑魔法圣殿的守卫者.如果你能通过我的挑战,那么你可以带走黑魔法圣殿的地图--"瞬

守卫者的挑战:三维dp

守卫者的挑战 难度级别: C: 编程语言:不限:运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 打开了黑魔法师 Vani 的大门,队员们在迷宫般的路上漫无目的地搜寻着关押 applepi 的监狱的所在地.突然,眼前一道亮光闪过.“我,Nizem,是黑魔法圣殿的守卫者.如果你能通过我的挑战,那么你可以带走黑魔法圣殿的地图……”瞬间,队员们被传送到了一个擂台上,最初身边有一个容量为 K 的包包.擂台赛一共有 N 项挑战,各项挑战依次进行.第

E. Nanosoft (预处理, 三维dp)

题目: 传送门 题意: 定义Nanosoft的 logo 为 四个大小相同的正方形合并成一个大正方形.左上角是红色的,右上角是绿色的,左下角是黄色的,右下角是蓝色的. 例如以下这些都是 以下这些都不是 给你一个n * m的矩阵,这个矩阵由 4 个大写字母 “R” ,  "G", “Y”, “B” 构成,这四个大写字母分别代表红色,绿色,黄色,蓝色.     有Q次询问,每次询问, 输入两个坐标,(x1, y1), (x2, y2) 代表 以 (x1, y1) 为矩阵左上角的坐标,(x2

Happy birthday hdu5234(三维dp)

http://acm.hdu.edu.cn/showproblem.php?pid=5234 题意:一个小姑娘生日了,她妈妈把她领到了一个花园(n*m)里面,起始坐标在(1,1),每个坐标位置都有(a[i][j])的食物,她只能向左或向下走,并且她的胃口最大为K,最终到达(n, m)的位置,问你在满足题意的情况下,她最多能够吃多少食物. 分析:完全照着dp模板写的,没想到1A,百度了一下,没想到大神的做法和我一样.... #include <iostream> #include <std

UVA 12063 Zeros and Ones(三维dp)

题意:给你n.k,问你有多少个n为二进制的数(无前导零)的0与1一样多,且是k的倍数 题解:对于每个k都计算一次dp,dp[i][j][kk][l]表示i位有j个1模k等于kk且第一位为l(0/1) 再次预处理mod[i][j]表示1的i次方模j等于几,具体看代码注释 import java.util.Scanner; public class Main{ static int Maxn=65; static int Maxk=101; //前i个数有j个1模给定的值余k且第一位为1或者0的总个

codevs1169传纸条 不相交路径取最大,四维转三维DP

这个题一个耿直的思路肯定是先模拟.. 但是我们马上发现这是具有后效性的..也就是一个从(1,1)开始走,一个从(n,m)开始走的话 这样在相同的时间点我们就没法判断两个路径是否是相交的 于是在dp写挂了之后..我们妥妥写了一发爆搜..vis的那种 一旦你用了vis数组之后..我们就不能再记忆化搜索了..因为你缺少记录vis数组的状态.. 去了记忆化..来了发纯爆搜..果然T了..但是在codevs上还得了30分..不错不错.. 不错个锤子,ACM就是TLE 贴TLE代码 #include <io