zoukankan      html  css  js  c++  java
  • 动态规划-记忆化搜索

    1.数字三角形

    学习链接:http://blog.csdn.net/zwhlxl/article/details/46225947

    输入样例:

    5
    7
    3 8
    8 1 0
    2 7 4 4
    4 5 2 6 5

    输出样例:

    30

    递归代码:

    #include <stdio.h>
    #include <memory.h>
    #include <math.h>
    #include <string>
    #include <vector>
    #include <set>
    #include <stack>
    #include <queue>
    #include <algorithm>
    #include <map>
    
    
    #define I scanf
    #define OL puts
    #define O printf
    #define F(a,b,c) for(a=b;a<c;a++)
    #define FF(a,b) for(a=0;a<b;a++)
    #define FG(a,b) for(a=b-1;a>=0;a--)
    #define LEN 101
    #define MAX 1<<30
    #define V vector<int>
    
    using namespace std;
    
    int num[LEN][LEN]; 
    int dp[LEN][LEN];
    int n;
    
    int getMax(int i,int j){
        if(dp[i][j]>=0) return dp[i][j]; 
        if(i==n) return num[i][j];
        int a=getMax(i+1,j);
        int b=getMax(i+1,j+1);
        dp[i][j]=max(a,b)+num[i][j];
        return dp[i][j];
    }
    
    int main(){
        freopen("数字三角形.txt","r",stdin);
        int i,j;
        scanf("%d",&n);
        for(i=1;i<=n;i++){
            for(j=1;j<=i;j++){
                I("%d",&num[i][j]);
            }
        }
        for(i=1;i<=n;i++)
            fill(dp[i],dp[i]+1+n,-1);
        printf("%d",getMax(1,1));
        return 0;
    }
    View Code

    循环代码:

    #include <stdio.h>
    #include <memory.h>
    #include <math.h>
    #include <string>
    #include <vector>
    #include <set>
    #include <stack>
    #include <queue>
    #include <algorithm>
    #include <map>
    
    #define I scanf
    #define OL puts
    #define O printf
    #define F(a,b,c) for(a=b;a<c;a++)
    #define FF(a,b) for(a=0;a<b;a++)
    #define FG(a,b) for(a=b-1;a>=0;a--)
    #define LEN 101
    #define MAX 1<<30
    #define V vector<int>
    
    using namespace std;
    
    int num[LEN][LEN]; 
    int dp[LEN][LEN];
    int n;
    
    int main(){
        freopen("数字三角形.txt","r",stdin);
        int i,j;
        scanf("%d",&n);
        for(i=1;i<=n;i++){
            for(j=1;j<=i;j++){
                I("%d",&num[i][j]);
            }
        }
        for(i=1;i<=n;i++)
            dp[n][i]=num[n][i];
        for(i=n-1;i>=1;i--){
            for(j=1;j<=i;j++){
                dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+num[i][j];
            }
        }
        printf("%d",dp[1][1]);
        return 0;
    }
    View Code

     2.滑雪

    测试数据演示:

    (测试数据呈螺旋形滑下)

    代码:

    #include <stdio.h>
    #include <memory.h>
    #include <math.h>
    #include <string>
    #include <vector>
    #include <set>
    #include <stack>
    #include <queue>
    #include <algorithm>
    #include <map>
    
    
    #define I scanf
    #define OL puts
    #define O printf
    #define F(a,b,c) for(a=b;a<c;a++)
    #define FF(a,b) for(a=0;a<b;a++)
    #define FG(a,b) for(a=b-1;a>=0;a--)
    #define LEN 200
    #define MAX 1<<30
    #define V vector<int>
    
    using namespace std;
    
    int n,m;
    int dp[LEN][LEN],a[LEN][LEN];
    int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
     
    void init(){
        int i,j;
        FF(i,n)FF(j,m){
            dp[i][j]=-1;
        }
    }
     
    int dfs(int x,int y){
        if(dp[x][y]!=-1)    //已经记录过了 
            return dp[x][y];
        dp[x][y]=1;
        int k;
        FF(k,4){//构造四个方向 
            int tx=x+dx[k],ty=y+dy[k];
            if(tx>=0 && tx<n && ty>=0 && ty<m && a[x][y]>a[tx][ty] ){
                dp[x][y]=max(dp[x][y],dfs(tx,ty)+1);
            }
        }
        return dp[x][y];
    }
    
    int main(){
    //    freopen("滑雪.txt","r",stdin);
    
        int i,j,N;
        I("%d",&N);
        while(N--){
            I("%d %d",&n,&m);
            FF(i,n)FF(j,m){
                I("%d",&a[i][j]);
            }
            int ans=0;
            F(i,0,n) F(j,0,m){
                init();
                ans=max(ans,dfs(i,j));
            }
            O("%d
    ",ans);
        } 
        return 0;
    } 
    View Code

    (感觉代码还不够优化,待调优)


      3.吃吃吃

    测试数据演示:

    (注意到只能从图中中间3个区域出发,题目疯狂卡我语文)

    代码:

    #include <stdio.h>
    #include <memory.h>
    #include <math.h>
    #include <string>
    #include <vector>
    #include <set>
    #include <stack>
    #include <queue>
    #include <algorithm>
    #include <map>
    
    
    #define I scanf
    #define OL puts
    #define O printf
    #define F(a,b,c) for(a=b;a<c;a++)
    #define FF(a,b) for(a=0;a<b;a++)
    #define FG(a,b) for(a=b-1;a>=0;a--)
    #define LEN 1000
    #define MAX 1<<30
    #define V vector<int>
    
    using namespace std;
    
    int dp[LEN][LEN];
    int a[LEN][LEN];
    int n,m;
    
    int dfs(int x,int y){
        if(dp[x][y]>-MAX){
            return dp[x][y]; 
        }
        if(x==1 ){//|| y==1 || y==m
            return a[x][y];
        }
        int dy[3]={-1,0,1};
        int i,j;
        for(i=0;i<3;i++){
            int ty=y+dy[i];
            if(ty>=1 && ty<=m){
                dp[x][y]=max(dp[x][y],dfs(x-1,ty)+a[x][y]);
            }
        }
        return dp[x][y];
    }
    
    int main(){
    //    freopen("吃吃吃.txt","r",stdin);
        int i,j;
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++){
            for(j=1;j<=m;j++){
                I("%d",&a[i][j]);
            }
        }
        
        int ans=0;
        for(j=0;j<3;j++){
            //initialize
            for(i=1;i<=n;i++) fill(dp[i],dp[i]+1+m,-MAX);
            ans=max(ans,dfs(n,m/2+j));
        }
        printf("%d",ans);
        return 0;
    }
    View Code

     4.传纸条

    测试数据演示:

    根据传统算法设计的DP矩阵:,与正确答案相悖。

     DP矩阵分析图:

    对角线一直从3=1+2(序号2)循环到10=n+m-1(序号length-1)

    理解:红块表示纸条1,蓝块表示纸条2,纸条1有i-1和i两个前驱,纸条2有j-1和j两个前驱。四个情况叠加有四种可能,对四种情况进行遍历取最大值

    代码:

    #include <stdio.h>
    #include <memory.h>
    #include <math.h>
    #include <cstring>
    #include <vector>
    #include <set>
    #include <stack>
    #include <queue>
    #include <algorithm>
    #include <map>
    
    #define I scanf
    #define OL puts
    #define O printf
    #define F(a,b,c) for(a=b;a<c;a++)
    #define FF(a,b) for(a=0;a<b;a++)
    #define FG(a,b) for(a=b-1;a>=0;a--)
    #define LEN 101
    #define MAX 1<<30
    #define V vector<int>
    
    using namespace std;
    
    int dp[LEN*2][LEN][LEN];
    //[对角线编号][纸条1纵坐标][纸条2纵坐标] 
    int a[LEN][LEN];
    
    int main(){
    //    freopen("D:/CbWorkspace/动态规划/传纸条.txt","r",stdin);
        int n,m,i,j,k;
        I("%d %d",&n,&m);
        F(i,1,n+1) F(j,1,m+1) I("%d",&a[i][j]);
        //首先对dp矩阵进行初始化
        memset(dp,-1,sizeof(dp));
        dp[2][1][1]=0;                    //顶点为0
        for(k=3;k<n+m;k++){                //对角线 
            for(i=1;i<m;i++){            //纸条1 纵坐标 
                for(j=i+1;j<=m;j++){    //纸条2 纵坐标(总是在纸条1右边)
                    //四种组合 
                    dp[k][i][j]=max(dp[k][i][j],dp[k-1][i][j]);
                    dp[k][i][j]=max(dp[k][i][j],dp[k-1][i-1][j]);
                    dp[k][i][j]=max(dp[k][i][j],dp[k-1][i][j-1]);
                    dp[k][i][j]=max(dp[k][i][j],dp[k-1][i-1][j-1]);
                    dp[k][i][j]+=a[k-i][i];        //纸条 1 的value 
                    dp[k][i][j]+=a[k-j][j];      //纸条 2 的value
                }
            } 
        } 
        O("%d",dp[n+m-1][m-1][m]);
        return 0;
    }
    View Code

  • 相关阅读:
    领域驱动设计学习笔记(一 事件总线)
    枚举位预算 (适用于权限和拥有多种枚举值)
    Javascript闭包(狗血剧情,通俗易懂)
    Xml序列化和反序列化
    Javascript轮播 支持平滑和渐隐两种效果(可以只有两张图)
    Git使用教程
    MySQL数据库基本用法-聚合-分组
    MySQL数据库基本用法-查询
    MySQL数据库基本用法
    JS中获取文件点之后的后缀字符
  • 原文地址:https://www.cnblogs.com/TQCAI/p/8438424.html
Copyright © 2011-2022 走看看