DP题目以及模型分类

数字三角形模型
AcWing 1015. 摘花生

#include <iostream>

using namespace std;
const int N = 110;
int w[N][N];
int f[N][N];
//f[i][j] 表示从(1,1)到(i,j)最多能够摘到的花生数;
[int main()
{
     int T;
     cin >> T;
     while(T--)
     {
        int n, m;
        cin >> n >> m;
        for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++) cin >> w[i][j];
        for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++) 
        	//从两个方向过来
            f[i][j] = max(f[i-1][j], f[i][j - 1]) + w[i][j];
        
        cout << f[n][m] << endl;
     }
     return 0;
}

AcWing 1018. 最低通行费

#include <iostream>

using namespace std;

const int N = 110, INF = 1e9;
int g[N][N], f[N][N];

int main()
{
    int n;
    cin >> n;
    for(int i = 1; i <= n; i++)
    for(int j = 1; j <= n; j++) cin >> g[i][j];
    
    //是求最小值  需要处理边界问题
    //!!!处理边界很重要
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            if(i == 1 && j == 1) f[i][j] = g[i][j];
            else
            {
                f[i][j] = INF;
                //从左边过来
                if(i > 1) f[i][j] = min(f[i][j], f[i - 1][j] + g[i][j]);
                //从上边过来
                if(j > 1) f[i][j] = min(f[i][j], f[i][j - 1] + g[i][j]);
            }
    cout << f[n][n] << endl;
    return 0;
}

AcWing 1027. 方格取数

#include <iostream>

using namespace std;

const int N = 15;
int g[N][N], f[N + N][N][N];
int a, b, c;
//f[k][i1][i2] 表示所有从(1,1),(1,1)分别走到(i1, k - i1),(i2, k -  i2)的路径的最大值
//其中k = i1 + j1 = i2 + j2
int main()
{
    int n;
    cin >> n;
    while(cin >> a >> b >> c, a || b || c) g[a][b] = c;
    
    //从(1, 1)开始
    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 = g[i1][j1];
                    if(i1 != i2) t += g[i2][j2];
                    int &x = f[k][i1][i2];  //引用  一变都跟着变
                    //下下   下右  右下  右右
                    //向右走时是j在变   i不变
                    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);
                }
            }
    cout << f[n + n][n][n] << endl;
    return 0;
}

AcWing 275. 传纸条

#include <iostream>

using namespace std;

const int N = 55;
int g[N][N], f[N + N][N][N];
int a, b, c;
//f[k][i1][i2] 表示所有从(1,1),(1,1)分别走到(i1, k - i1),(i2, k -  i2)的路径的最大值
//k = i1 + j1 = i2 + j2
int main()
{
    int n, m;
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            cin >> g[i][j];
    
    //从(1, 1)开始
    for(int k = 2; k <= n + m; k++)
    //因为有 1 <= x1 <= n   1 <= k - x1 <= m
        for(int i1 = max(1, k - m); i1 <= min(k - 1, n); i1++)
            for(int i2 = max(1, k - m); i2 <= min(k - 1, n); i2++)
            {
                int t = g[i1][k - i1];
                if(i1 != i2) t += g[i2][k - i2];   
                int &x = f[k][i1][i2];  //引用  一变都跟着变
                //下下   下右  右下  右右
                //向右走时是j在变   i不变
                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);
            }
    cout << f[n + m][n][n] << endl;
    return 0;
}

最长上升子序列模型
AcWing 1017. 怪盗基德的滑翔翼

#include <iostream>

using namespace std;
const int N = 110;
int a[N], f[N];  //f[i] 表示到从0到i的递增长度
//求最长上升子序列  或者是最长下降子序列
int main()
{
    int T;
    cin >> T;
    while(T--)
    {
        int n;
        cin >> n;
        for(int i = 1; i <= n; i++) cin >> a[i];
        
        int res = 0;
        for(int i = 1; i <= n; i++)
        {
            f[i] = 1;
            for(int j = 1; j < i; j++)
                if(a[i] > a[j]) 
                    f[i] = max(f[i], f[j] + 1); 
            res = max(res, f[i]);
        }
        for(int i = n; i > 0; i--)
        {
            f[i] = 1;
            for(int j = n; j > i; j--)
                if(a[i] > a[j]) 
                    f[i] = max(f[i], f[j] + 1); //一直算以f[i]结尾的长度
            res = max(res, f[i]);
        }
        cout << res << endl;
    }
    return 0;
}

AcWing 1014. 登山

#include <iostream>

using namespace std;
const int N = 1010;
int a[N], f[N], g[N];
//即是求先上升后下降的最大长度
int main()
{
    int n;
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    
    for(int i = 1; i <= n; i++)
    {
        f[i] = 1;
        for(int j = 1; j < i; j++)
            if(a[i] > a[j]) 
                f[i] = max(f[i], f[j] + 1);
    }
    
    for(int i = n; i > 0; i--)
    {
        g[i] = 1;
        for(int j = n; j > i; j--)
            if(a[i] > a[j]) 
                g[i] = max(g[i], g[j] + 1);
    }
    int res = 0;
    for(int i = 1; i <= n; i++) res = max(res, f[i] + g[i] - 1);
    //减1是因为重复计算了两次
    cout << res << endl;
    return 0;   
}

AcWing 482. 合唱队形

//代码和上题基本上一致  题目本意也是基本一致
#include <iostream>

using namespace std;
const int N = 110;
int a[N], f[N], g[N];

int main()
{
    int n;
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    
    for(int i = 1; i <= n; i++)
    {
        f[i] = 1;
        for(int j = 1; j < i; j++)
            if(a[i] > a[j])
                f[i] = max(f[i], f[j] + 1);
    }
    
    for(int i = n; i; i--)
    {
        g[i] = 1;
        for(int j = n; j > i; j--)
            if(a[i] > a[j])
                g[i] = max(g[i], g[j] + 1);
    }
    
    int res = 0;
    for(int i = 1; i <= n; i++) res = max(res, f[i] + g[i] - 1);
    cout << n - res << endl;
    return 0;
}

AcWing 1012. 友好城市

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;
typedef pair<int, int> PII;
const int N = 5010;
int f[N], n;
PII q[N];

int main()
{
    cin >> n;
    
    for(int i = 0; i < n; i++) cin >> q[i].first >> q[i].second;
    sort(q, q + n);   //需要排序  注意下标问题
    int res = 0;
    for(int i = 0; i < n; i++)
    {
        f[i] = 1;
        for(int j = 0; j < i; j++)
            if(q[i].second > q[j].second)
                f[i] = max(f[i], f[j] + 1);
        res = max(res, f[i]);
    }
    cout << res << endl;
    return 0;
}

AcWing 1016. 最大上升子序列和

#include <iostream>

using namespace std;

const int N = 1010;
int a[N], f[N];
//注意状态表示和状态计算
int main()
{
    int n;
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    
    int res = 0;;
    for(int i = 1; i <= n; i++)
    {
        f[i] = a[i];
        for(int j = 1; j < i; j++)
            if(a[i] > a[j])
            {
                f[i] = max(f[i], f[j] + a[i]);
            }
        res = max(res, f[i]);
    }
    cout << res << endl;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值