0
点赞
收藏
分享

微信扫一扫

【算法专项】动态规划专项四

悲催博士僧 2022-01-15 阅读 51

动态规划三--------点击此处
动态规划二--------点击此处
动态规划一--------点击此处

动态规划(dp)核心原理是分类加法原理和分布乘法原理。,在当状态的上一个或几个状态中找出最优解求得当前状态,而对于前一个或者几个状态采用同样的方法直到求出边界状态。

一定要满足下面几点:
1.具有相同子问题。可以分解出几个子问题。
2.满足最优化原理(最优子结构)一个最优决策。
3.具有无后效性:要求每一个问题的决策不能够对解决其它未来的问题产生影响,如果产生影响那么无法保证其最优性。

下面以2道有一定难度的题目进行讲解。

目录

加括号求最大值

我们怎么思考这个问题呢?以下均是我个人理解。
首先肯定要遍历从第一个数到第n个数的,那么设一个函数Max(i,j)表示第i个整数到第j个整数加上一层括号的最大值。那么其实我们需要解决的就是子式的最大值了。我们知道正数乘正数表达式是最大的,所以有效利用好这个乘号。
当然题目要求只有加法和乘法,那其实稍微简单了,我们只要选出乘号,并标记为1,那么加号自然就是0了。注意到,有n个数,那么必然有n-1个符号,那么我们将符号和数字的顺序绑定一起,把初始工作完成。
那么有个疑惑,就是如何保存已搜索的信息,那么设立一个结构体,里面要包含最大值和最小值,表示的就是第i个数到第j个数的情况,有人要问了为什么要保存最小值呢?便于更好地区分,其实加不加也无所谓。
那么子问题是什么呢,就是i到j的情况。通过设立一个中转变量来处理好括号的存在。如果前面小了继续向上推,直到这个中转变量到达了j处(就是最后的n)
下面附代码:

#include <iostream>
#include <cstdio>

#define SUM 101
#define Max 100000000
#define Min -100000000

using namespace std;

int n,num[SUM],ope[SUM];//ope表示存放运算符,num存放数

struct rem{
    int max;
    int min;
};

rem result[SUM][SUM];

rem cmp(int a1,int a2,int a3,int a4){
    int max=Min,min=Max,temp=0;
    if((temp=a1*a3)>max) max=temp;
    if(temp<min) min=temp;
    if((temp=a1*a4)>max) max=temp;
    if(temp<min) min=temp;
    if((temp=a2*a3)>max) max=temp;
    if(temp<min) min=temp;
    if((temp=a2*a4)>max) max=temp;
    if(temp<min) min=temp;
    rem p;
    p.max=max;
    p.min=min;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
    return p;
}

//max[i][j]表示第i个整数到第j个整数加上括号得到的最大值,这样最终结果就是MAX[1][n]
rem MAX(int i,int j){
    if(i==j){
        result[i][j].max=num[i];
        result[i][j].min=num[i];
        return result[i][j];
    }
    if(i<j){
        if(result[i][j].max!=Min){
            return result[i][j];
        }else{
            for(int t=i;t<j;t++){
                rem tempa=MAX(i,t);
                rem tempb=MAX(t+1,j);
                if(ope[t]==1){
                    rem c=cmp(tempa.max,tempa.min,tempb.max,tempb.min);
                    if(c.max>result[i][j].max) result[i][j].max=c.max;
                    if(c.min<result[i][j].min) result[i][j].min=c.min;
                }else{
                    int mm=tempa.max+tempb.max;
                    if(mm>result[i][j].max) result[i][j].max=mm;
                    int mi=tempa.min+tempb.min;
                    if(mi<result[i][j].min) result[i][j].min=mi;
                }
            }
            return result[i][j];
        }
    }
    //return result[i][j];
}

int main(){
    int i,j;
    char ch;
    while(cin>>n){
        for(i=1;i<n;i++){
            cin>>num[i];
            getchar();
            cin>>ch;
            if(ch=='*') ope[i]=1;
            else ope[i]=0;
        }
        cin>>num[n];

        for(i=0;i<=n;i++){
            for(j=0;j<=n;j++){
                result[i][j].max=Min;
                result[i][j].min=Max;
            }
        }
        int max=MAX(1,n).max;
        cout<<max<<endl;
    }
    return 0;
}

猴子快乐

分析:用max[i][j]表示在第i时间在第j个柱子上时能得到的最大的幸福值;grid[i][j]表示第i时间第j柱子是否有虫子。那么mx[i][j]=Max(mx[i-1][j-1],m[i-1[j],mx[i-1][j+1])+grid[j][i].边界问题要特别注意。

#include <iostream>

#define MAX 1<<29
#define N 100
#define T 10100

using namespace std;

int mx[T][N],grid[N][T];

int n,limt;

int Max(int a,int b,int c){
    int z;
    z=(a>b)?a:b;
    return z>c?z:c;
}

int main(){
    while(cin>>n>>limt){
        for(int i=1;i<=n;i++){
            for(int j=0;j<limt;j++){
                cin>>grid[i][j];
            }
        }

        for(int i=1;i<=n;i++){
            for(int j=0;j<limt;j++){
                mx[j][i]=-MAX;
            }
        }

        mx[0][1]=grid[1][0];
        for(int i=1;i<limt;i++){
            for(int j=1;j<=n&&j<=i+1;j++){
                int a=-MAX,b=-MAX,c=-MAX;
                if(j>1) a=mx[i-1][j-1];
                b=mx[i-1][j];
                if(j<n) c=mx[i-1][j+1];
                mx[i][j]=Max(a,b,c)+grid[j][i];
            }
        }

        int mxmx=0;
        for(int i=1;i<=n;i++){
            if(mx[limt-1][i]>mxmx) mxmx=mx[limt-1][i];
        }
        cout<<mxmx<<endl;
    }
    return 0;
}
举报

相关推荐

0 条评论