动态规划-记忆化搜索

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\n",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

 


 

posted @ 2018-02-10 11:54  TQCAI  阅读(245)  评论(0编辑  收藏  举报