动态规划1

递推

无后效性,最优子结构

-》状态转移方程     -》   注意初始化 (边界值) -》注意枚举顺序(完全背包第二维从小到大,01背包从大到小,区间先长度再左)

LIS接上之前最优解,LCS,背包问题(01背包,完全背包,分组背包,依赖性问题)

状态压缩,树形dp

看过最好的一篇讲解动态规划的

https://mp.weixin.qq.com/s/15HSidWyGg5eN--ICNNjFg

微信里的一篇文章。看完之后,基本的动态规划思想就懂了,有特点的dp需要再学习,剩下的就要刷题了。


Vijos / 题库 /

过河

数据过大,状压;
#include<iostream> #include<algorithm> #include<cstring> using namespace std; #define maxn 1000001 int a[maxn],d[maxn],v[maxn],s,t; int main() { int l,m,x; cin>>l>>s>>t>>m; memset(d,0x7f7f7f7f,sizeof(d)); for(int i=1;i<=m;i++) cin>>x,a[x]=1; v[0]=1,d[0]=0; for(int i=1;i<=l;i++) { for(int j=0;j<i;j++) { if(i-j<s||i-j>t||!v[j]) continue; v[i]=1; if(a[i]){ d[i]=min(d[i],d[j])+1; } else d[i]=min(d[i],d[j]); } } cout<<d[l]; return 0; }

Vijos / 题库 /

清帝之惑之顺治

先自顶向上,随机选取某个点i,i是由哪些点转移过来。
刚开始没想那么多,直接顺序枚举图,但结果不对,
因为如果map[i][j]的高度小于四周,四周其实目前还没有修改,仍是初始状态
等到四周的值都改了之后,又回不到该点
#include<iostream> #include<algorithm> #include<cstring> using namespace std; #define maxn 601 int ma[maxn][maxn],d[maxn][maxn]; struct m{ int x,y; int hight; }g[251000]; bool compare(m i,m j) { return i.hight>j.hight; }//将图上的高度进行排序 int main() { int r,c,ans=0,k=0; cin>>r>>c; for(int i=1;i<=r;i++) for(int j=1;j<=c;j++){ cin>>ma[i][j]; g[++k].x=i,g[k].y=j; g[k].hight=ma[i][j]; d[i][j]=1;//注意初始化,刚开始没考虑,结果就过了两个测试点 } sort(g+1,g+1+k,compare); for(int i=1;i<=k;i++)//枚举,上下左右 { int w=g[i].x,u=g[i].y; if(ma[w][u]>ma[w-1][u]&&(w-1)>0) { d[w-1][u]=max(d[w][u]+1,d[w-1][u]); } if(ma[w][u]>ma[w+1][u]&&w+1<=r) { d[w+1][u]=max(d[w][u]+1,d[w+1][u]); } if(ma[w][u]>ma[w][u-1]&&u-1>0) { d[w][u-1]=max(d[w][u]+1,d[w][u-1]); } if(ma[w][u]>ma[w][u+1]&&u+1<=c) { d[w][u+1]=max(d[w][u]+1,d[w][u+1]); } } for(int i=1;i<=r;i++) for(int j=1;j<=c;j++) ans=max(ans,d[i][j]); cout<<ans; return 0; }

 最大子矩阵和问题

#include<iostream>
#include<algorithm>
#include<cmath>
#include<set>
#include<cstring>
using namespace std;
#define max2 1111
#define rson ((pos)*2+1)
#define lson ((pos)*2)
int dp[max2],c[max2],ans=0,sum,line1[max2],line[max2],a[max2][max2],n,m;
int main()
{
    int pos1,pos2,lin1=0x3f3f3f3f,lin2=0;//pos1,pos2分别代表子矩阵起始行和末位行,lin1,lin2代表子矩阵列号
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        cin>>a[i][j];
    for(int i=1;i<=n;i++)//方法,将二维矩阵转换成一维,对于r~l行,其中每一列的元素和为b[j],此时该子矩阵的最大和相当于最大连续列的和相加即求最大连续子序列
    {
        memset(c,0,sizeof(c));
        for(int j=i;j<=n;j++){//i为子矩阵起始行,j为子矩阵末尾行
            for(int k=1;k<=m;k++)//对于行号为i,j大小的子矩阵,对其列的和进行计算
            c[k]+=a[j][k];
            int dp=0;
            for(int h=1;h<=m;h++)//连续列的最大值
            {
                if(dp>0){dp+=c[h],line1[h]=1;}
                else{memset(line1,0,sizeof(line1)),dp=c[h];line1[h]=1;}
                if(ans<dp){
                    ans=dp;
                    lin1=0x3f3f3f3f,lin2=0;
                    for(int u=1;u<=m;u++) if(line1[u]) lin1=min(lin1,u),lin2=max(lin2,u);;
                }
            }
            if(sum<ans){
                    sum=ans;
                pos1=i,pos2=j;
            }
            memset(line,0,sizeof(line));
        }
    }
   cout<<sum<<endl;
   cout<<pos1<<' '<<pos2<<' '<<lin1<<' '<<lin2;//输出该子矩阵的行号和列号
    return 0;
}
原文地址:https://www.cnblogs.com/Showend/p/12359310.html