动态规划之数字三角形模型+最长上升子序列模型

首先,我们从集合角度重新看待DP:

直接看题:https://www.acwing.com/problem/content/1029/

就是取纸条的原题,我们令fi1,j1,i2,j2表示从(1,1),(1,1)分别走到(i1,j1),(i2,j2)的路径的max

i1+j1==i2+j2,于是我们可以把状态变为fk,i1,i2表示走到(i1,k-i1),(i2,k-i2)的最大值。

对于最后一个状态,我们可以按照上下分成4中,同时转移时重合的化加wij,否则就分别加一个

下面是AC代码:

cpp 复制代码
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 15;

int n;
int w[N][N];
int f[N * 2][N][N];

int main()
{
    scanf("%d", &n);

    int a, b, c;
    while (cin >> a >> b >> c, a || b || c) w[a][b] = c;

    for (int k = 2; k <= n + n; k ++ )
        for (int i1 = 1; i1 <= n; i1 ++ )
            for (int i2 = 1; i2 <= n; i2 ++ )
            {
                int j1 = k - i1, j2 = k - i2;
                if (j1 >= 1 && j1 <= n && j2 >= 1 && j2 <= n)
                {
                    int t = w[i1][j1];
                    if (i1 != i2) t += w[i2][j2];
                    int &x = f[k][i1][i2];
                    x = max(x, f[k - 1][i1 - 1][i2 - 1] + t);
                    x = max(x, f[k - 1][i1 - 1][i2] + t);
                    x = max(x, f[k - 1][i1][i2 - 1] + t);
                    x = max(x, f[k - 1][i1][i2] + t);
                }
            }

    printf("%d\n", f[2*n][n][n]);
    return 0;
}

接题:https://www.acwing.com/problem/content/189/

看到数据范围可以确定爆搜(BFS因为一层层存储量太大不推荐),这样就转换成导弹拦截的思路了:从前往后,对于一个导弹找到比他高的min插入即可,若没有就再开一个(注意防御系统一定是递增的)

下面是AC代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n;
int a[10001];
int ans=50;
int up[100010],down[10000];
void dfs(int x,int u,int d)
{
    if(u+d>=ans) return;
    if(x==n+1){
        ans=min(ans,u+d);
        return;
    }
    //先上
    int f=-1;
    for(int i=1;i<=u;i++)
    {
        if(up[i]>a[x]){
            f=i;
            break;
        }
        if(i==u) f=-1;
    }
    if(f==-1){
        up[u+1]=a[x];
        dfs(x+1,u+1,d);
        up[u+1]=0;
    }
    else{
        int t=up[f];
        up[f]=a[x];
        dfs(x+1,u,d);
        up[f]=t;
    }
    f=-1;
    for(int i=1;i<=d;i++)
    {       if(down[i]<a[x]){
            f=i;
            break;
        }
        if(i==d) f=-1;
    }
    if(f==-1){
        down[d+1]=a[x];
        dfs(x+1,u,d+1);
        down[d+1]=0;
    }
    else{
        int t=down[f];
        down[f]=a[x];
        dfs(x+1,u,d);
        down[f]=t;
    }
}
int main()
{
    while(cin>>n)
    {
        if(!n) break;
        for(int i=1;i<=n;i++) cin>>a[i];
        memset(up,0,sizeof(up));
        memset(down,0,sizeof(down));
        ans=50;
        dfs(1,0,0);
        cout<<ans<<endl;
    }
}

接题:https://www.acwing.com/problem/content/1018/

确定fij的集合:由第一个序列前i个字母,第二个前j个并以bj的公共上升子序列。

表示max,然后考虑计算:先按是否包含ai分成两类:不包含:fi-1j,包含:ai==bj

我们又可以把b分为以b1...bj-1以及空,对于bk就是fi-1k+1

下面是AC代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n,a[100010],b[100010];
int dp[3010][3005];
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) cin>>b[i];
    for(int i=1;i<=n;i++)
    {
        int maxv=0;
        for(int j=1;j<=n;j++)
        {
             
             dp[i][j]=dp[i-1][j];
             if(a[i]==b[j])
             {
                 dp[i][j]=max(dp[i][j],1);
                 dp[i][j]=max(dp[i][j],maxv);
                 
             }
             if(b[j]<a[i]) maxv=max(maxv,dp[i-1][j]+1);
        }
    }
    int res=0;
    for(int i=1;i<=n;i++) res=max(res,dp[n][i]);
    cout<<res;
}
相关推荐
通信小呆呆2 小时前
当算法有了“五感”:多模态数据融合如何向人体感官协同学习?
人工智能·学习·算法·机器学习·机器人
benben0442 小时前
强化学习之DQN算法族(基于gymnasium开发)
算法
玖玥拾3 小时前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
何以解忧,唯有..4 小时前
Go语言循环语句详解:for、range与循环控制
开发语言·算法·golang
想吃火锅10054 小时前
【leetcode】88.合并两个有序数组js
算法
один but you5 小时前
constexpr函数
c++
生成论实验室5 小时前
机器人:一个自主运动的系统
人工智能·算法·语言模型·机器人·自动驾驶·agi·安全架构
Qres8215 小时前
算法复键——树状数组
数据结构·算法
H178535090965 小时前
SolidWorks第四部分_直接实体建模特征9_替换面原理
线性代数·算法·机器学习·3d建模·solidworks