zoukankan      html  css  js  c++  java
  • 多阶段决策问题

    我们在解决动态规划问题的时候,往往不会很轻松的写出递推方程。这时候我们需要考虑一下是否需要借鉴"多阶段决策问题"。

    https://www.cnblogs.com/woxiaosade/p/10346052.html

    上面的这道“硬币问题”的题目,如果将每一枚硬币的数目改成1,那原先的递推方程就很难写出了,我们不知道何时拿硬币,拿哪一枚硬币。

    如果我们将每一枚硬币的标号,视作一个“阶段”,每一个阶段,单独对一个硬币进行分析,就只有两种情况(拿 与 不拿),再循环访问其他硬币,问题就很好解决。

    下面给出两个例子,希望可以对比之前较单一的dp问题。

    单向TSP

    问题描述:

      给一个m行n列( m<=10 , n <= 100) 的整数矩阵,从第一列的任何位置出发,每次可以向右,右上,右下走一格,最终到达最后一列的任一行。要求经过的整数之和最小。

    注意:

      整个矩阵是环形的,第一行的上一行是最后一行,最后一行的上一行是第一行。多解时,请输出字典序最小的解。

    题目分析:

      如果我们设d [ i ] 为第 i 列到最后一列的最小和,我们按照以往的经验写出递推方程 

      [d[i][j] = mathop {max }limits_j (a[i][j]) + d[i + j])]

      显然这个方程是错误的,我们不确定 min{ a[ i ][ j ] } 是否能达到 d [ i + 1 ] 的那一个 a [ i + 1] [ j ]。这个时候,我们要考虑将数组 d 扩大为二维。

      这时候,d [ i ][ j ] 设为 从 格子 a[ i ][ j ] 出发到达最后一列的最小整数和。这个时候我们再尝试一下写递推方程,

      [d[i][j] = mathop {max }limits_{0 <  = k <  = 2} (a[i][j]) + d[nex{ m{t}}\_rows[k]][j + 1])]

    #include <stdio.h>
    #include <iostream>
    #include <algorithm>
    #define inf 0x3f3f3f3f
    using namespace std;
    int m, n;
    int a[15][105];
    int next[15][105];
    int d[15][105];
    int first = 0, ans = inf ; 
    int dp2(int i, int j){//递归 
        if(j == n){
            d[i][j] = a[i][j];
            return a[i][j];
        }
        if(d[i][j])
            return d[i][j];
        d[i][j] = inf;
        int rows[3] = {i, i - 1, i + 1};//行号 直行 右上 右下 
        if(i == 1)    rows[1] = m;
        if(i == m)    rows[2] = 1;
        for(int k = 0; k < 3; k++){
            if(dp2(rows[k], j+1) + a[i][j] < d[i][j]){
                d[i][j] = dp2(rows[k], j+1) + a[i][j];
                next[i][j] = rows[k];
            }
        }
        if(j == 0 && d[i][j] < ans){
            ans = d[i][j];
            first = i;
        }
        return d[i][j];
    }
    
    void dp1(){//循环 
        for(int i=n;i>0;i--){//逆推列 
            for(int j=1;j<=m;j++){//
                if(i==n)
                    d[j][i] = a[j][i];
                else{
                    d[j][i] = inf;
                    int rows[3] = {j, j - 1, j + 1};//行号 直行 右上 右下 
                    if(j == 1)    rows[1] = m;
                    if(j == m)    rows[2] = 1;
                    sort(rows,rows+3);//保证行号字典序最小 
                    for(int k = 0; k<3;k++){
                        if(d[rows[k]][i+1] + a[j][i] < d[j][i]){
                            d[j][i] = d[rows[k]][i+1] + a[j][i];
                            next[j][i] = rows[k];
                        }
                    } 
                }
                if(j == 0 && d[j][i] < ans){
                    ans = d[j][i];
                    first = j;
                }
            }
        }
    }
    
    int main(){
        scanf("%d %d", &m, &n);
        for(int i=1;i<=m;i++)
            for(int j=1;j<=n;j++)
                scanf("%d", &a[i][j]);     
        for(int i=1;i<=m;i++)
            dp2(i,1);    
        //dp2(1,5);
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++)
                cout<<d[i][j]<<" ";
            cout<<endl;
        }
        return 0;
    }
    View Code

      如果要输出路径,最好设一个next[ i ][ j ] 数组,来记录 格子( i , j )下一行是哪一行。

    0 - 1 背包问题

    问题描述:

      有n种物品,每种只有一个,第 i 种 物品的体积为Vi ,重量为 Wi。选一些物品装到一个容量为C的背包,使得总体积不超C的情况下,重量尽量大。

     问题分析:

      模仿上题,将每一个物品看作一个“阶段” ,设d [ i ][ j ] 为第 i 到第 n 个物品,装入到容量为 j 的背包中的最大重量。

      递推公式:  d[ i ][ j ] = max ( d( i + 1 , j) ,  d( i + 1 , j - V[ i ] ) + W[ i ])    (此物品选择 不装 与 装)

    附部分代码

    for(int i = n; i >= 1; i--){
        for(int j = 0; j <= c; j++){
            d[i][j] = (i == n ? 0 : d[i+1][j]);
            if(j >= V[i])
                d[i][j] = max(d[i][j], d[i+1][j - V[i]] + W[i]);
        }
    }

    递归代码如下

    int dp(int p, int w) {
        if (d[p][w]) return d[p][w];
        if (p < n) {
            if (w >= g[p].w)
                d[p][w] = max(dfs(p + 1, w), dfs(p + 1, w - g[p].w) + g[p].v);
            else
                d[p][w] = dfs(p + 1, w);
        }
        else {
            if (w >= g[p].w)
                d[p][w] = g[p].v;
            else
                d[p][w] = 0;
        }
        return d[p][w];
    }

     参考文献:

    《算法竞赛入门经典 (第2版)》刘佳汝 P270

  • 相关阅读:
    1、Java语言概述与开发环境——Java程序运行机制
    1、Java语言概述与开发环境——JDK的安装与环境变量的配置
    针孔成像模型
    anconda下安装opencv
    用Navicat Prenium12连接Oracle数据库(oracle11g版本)时报错ORA-28547:connection to server failed,probable Oracle Net admin error.解决办法
    JQueryEsayUI的datagrid分页
    java中String和int的互相转化
    js页面刷新
    oracle的正则表达式
    EL表达式中,param和requestScope的区别
  • 原文地址:https://www.cnblogs.com/woxiaosade/p/10350630.html
Copyright © 2011-2022 走看看