kuangbin带你飞专题十四基础DP

本文精选了多个ACM竞赛中的经典算法题目进行详细解析,包括动态规划、贪心算法等,通过具体实例展示了每种算法的应用场景及实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HDU 1024 Max Sum Plus Plus

题意

你有n个数s1, s2…sn,给你一个整数m,求m个子段和的最大值

思路

在这里插入图片描述

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>

using namespace std;
const int maxn = 1e6 + 10;
const int inf = 0x7ffffff;

int a[maxn];
int f[maxn];
int Max[maxn];

int main() {
    int n, m, mmax;
    while(~scanf("%d%d", &m, &n)) {
        for(int i = 1; i <= n; i ++) {
            scanf("%d", &a[i]);
        }

        memset(f, 0, sizeof f);
        memset(Max, 0, sizeof Max);

        for(int i = 1; i <= m; i ++) {
            mmax = -inf;
            for(int j = i; j <= n; j ++) {
                f[j] = f[j - 1];

                f[j] = max(f[j - 1] + a[j], Max[j - 1] + a[j]);
                // 用Max[i] 保存i - 1组 考虑前j-1个数的最大值, 降低了一层循环
                Max[j - 1] = mmax;
                mmax = max(mmax, f[j]);
            }
        }

        printf("%d\n", mmax);
    }

    return 0;
}

HDU1029Ignatius and the Princess IV

思路

摩尔投票算法

代码

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 1000010;

int a[N];
int n, x, num, cnt;

int main() {
    int n;
    while(~scanf("%d", &n)) {
        num = 0, cnt = 0;
        for(int i = 1; i <= n; i ++) {
            cin >> x;
            if(x == num) cnt ++;
            else {
                if(cnt == 0) {cnt ++, num = x;}
                else cnt --;
            }
        }
        cout << num << endl;
    }

    return 0;
}

HDU1069 Monkey and Banana

思路

简单的LIS,只不过判断的时候要判断两个属性,宽和高

注意

next_permutation用法

sort(a , a + n); //这里忘了,导致全排列没求完整

do {

}while(next_permutation(a, a + n))

代码

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;
const int N = 1010;

struct Brick{
    int x, y, z;
}brick[N];

int n;
int num[3];
int f[N];

bool cmp(Brick a, Brick b) {
    if(a.x == b.x)
        return a.y < b.y;
    return a.x < b.x;
}

int main(){
    int k = 1;
    while(~scanf("%d", &n)) {
        if(!n) break;
        int cnt = 0;
        for(int i = 0; i < n; i ++) {
            int a, b, c;
            cin >> a >> b >> c;
            num[0] = a, num[1] = b, num[2] = c;
            sort(num, num + 3);
            do {
                brick[cnt].x = num[0], brick[cnt].y = num[1], brick[cnt].z = num[2], cnt ++;
            }while(next_permutation(num, num +3));
        }

        sort(brick, brick + cnt, cmp);
        memset(f, 0, sizeof f);
        int ans = 0;
        for(int i = 0; i < cnt; i ++){
            f[i] = brick[i].z;
            for(int j = 0; j < i; j ++) {
                if(brick[j].x < brick[i].x && brick[j].y < brick[i].y) {
                    f[i] = max(f[i], f[j] + brick[i].z);
                }
            }
            ans = max(ans, f[i]);
        }

        printf("Case %d: maximum height = %d\n", k ++, ans);
    }

    return 0;
}

HDU 1087 Super Jumping! Jumping! Jumping

思路

LIS模板题

代码

在这里插入代码片#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 1010;
int f[N];
int ans;
int a[N];

int main() {
    int n;
    while(~scanf("%d", &n) && n) {
        for(int i = 0; i < n; i ++)
            scanf("%d", &a[i]);
        memset(f, 0, sizeof f);
        ans = 0;
        for(int i = 0; i < n; i ++) {
            f[i] = a[i];
            for(int j = 0; j < i; j ++) {
                if(a[j] < a[i]) {
                    f[i] = max(f[i], f[j] + a[i]);
                }
            }
            ans = max(ans, f[i]);
        }

        cout << ans << endl;
    }

    return 0;
}

HDU 1114 Piggy-Bank

思路

完全背包模板题咯
状态表示: f [ i ] [ j ] : 考 虑 前 i 个 物 品 , 体 积 恰 好 为 j 的 所 有 选 法 f[i][j]:考虑前i个物品, 体积恰好为j的所有选法 f[i][j]:i,j
属性: m i n min min
状态计算(滚动数组): f [ j ] = m i n ( f [ j ] , f [ j − v ] + w ) f[j] = min(f[j], f[j - v] + w) f[j]=min(f[j],f[jv]+w)
初始化: f [ 0 ] = 0 , f[0] = 0, f[0]=0, 其他 f [ i ] = + ∞ f[i] = +∞ f[i]=+

代码

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 510, M = 10010;
int w, v;
int f[M];

int main() {
    int T;
    scanf("%d", &T);
    while(T --) {
        memset(f, 0x3f, sizeof f);
        int a, b;
        scanf("%d%d", &a, &b);
        int m = b - a;
        int n;
        scanf("%d", &n);
        f[0] = 0;
        for(int i = 1; i <= n; i ++) {
            scanf("%d%d", &w, &v);
            for(int j = 0; j <= m; j ++) {
                if(j >= v) f[j] = min(f[j], f[j - v] + w);
            }
        }

        if(f[m] != 0x3f3f3f3f) printf("The minimum amount of money in the piggy-bank is %d.\n", f[m]);
        else puts("This is impossible.");
    }


    return 0;
}

HDU 1176 免费馅饼

思路

数塔问题, DP倒着推
状态表示 f [ i ] [ j ] f[i][j] f[i][j]: 走了 i i i秒, 且当前位置在 j j j的所有走法
属性: m a x max max
状态计算: f [ i ] [ j ] = m a x ( f [ i + 1 ] [ j − 1 ] , m a x ( f [ i + 1 ] [ j ] , f [ i + 1 ] [ j + 1 ] ) ) + a [ i ] [ j ] ; f[i][j] = max(f[i + 1][j - 1], max(f[i + 1][j], f[i + 1][j + 1])) + a[i][j]; f[i][j]=max(f[i+1][j1],max(f[i+1][j],f[i+1][j+1]))+a[i][j];

代码

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 100010;
int f[N][15];
int a[N][15];

int main() {
    int n;
    while(~scanf("%d", &n) && n) {
        memset(a, 0, sizeof a);
        memset(f, 0, sizeof f);
        int maxx = 0;
        for(int i = 0; i < n; i ++) {
            int p, t;
            scanf("%d%d", &p, &t);
            // 坐标向右偏移一个位置
            a[t][++ p] ++;
            maxx = max(maxx, t);
        }

        for(int i = maxx; i >= 0; i --) {
            for(int j = 1; j <= 11; j ++){
                f[i][j] = max(f[i + 1][j - 1], max(f[i + 1][j], f[i + 1][j + 1])) + a[i][j];
            }
        }

        printf("%d\n", f[0][6]);
    }

    return 0;
}

HDU1260 Tickets

思路

状态表示 f [ i ] f[i] f[i]: 前i个人买完的所有买法
属性: m i n min min
状态计算: f [ i ] = m i n ( f [ i − 1 ] + a [ i ] , f [ i − 2 ] + b [ i ] ) ; f[i] = min(f[i - 1] + a[i], f[i - 2] + b[i]); f[i]=min(f[i1]+a[i],f[i2]+b[i]);

代码

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 2010;
int a[N], b[N];
int f[N];

int main() {
    int n, T;
    scanf("%d", &T);
    while(T --) {
        scanf("%d", &n);
        for(int i = 1; i <= n; i ++)
            scanf("%d", &a[i]);
        for(int i = 2; i <= n; i ++)
            scanf("%d", &b[i]);
        f[0] = 0;
        f[1] = a[1];
        for(int i = 2; i <= n; i ++)
            f[i] = min(f[i - 1] + a[i], f[i - 2] + b[i]);

        int h = 8;
        h += f[n] / 3600;
        int m = f[n] / 60 % 60;
        int s = f[n] % 60;

        if(h < 12) {
            printf("%02d:%02d:%02d am\n", h, m, s);
        }
        else {
            printf("%02d:%02d:%02d pm\n", h - 12, m, s);
        }
    }

    return 0;

}

HDU1257最少拦截系统

思路

贪心可过, 能放就放, 不能新开一个导弹系统

代码

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 1e6 + 10;

int a[N], q[N];

int main() {
    int n;
    while(~scanf("%d", &n)) {
        int cnt = 0;
        for(int i = 0; i < n; i ++) {
            scanf("%d", &a[i]);
            int k = 0;
            while(k < cnt && q[k] < a[i]) k ++;
            if(k == cnt) q[cnt ++] = a[i];
            else q[k] = a[i];
        }
        printf("%d\n", cnt);
    }


    return 0;
}

HDU1160 FatMouse’s Speed

思路

LIS, 输出路径采用倒着枚举,妙啊

代码

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 1010;
int f[N];

struct Mouse {
    int id;
    int w;
    int speed;
}mouse[N];

bool cmp(Mouse a, Mouse b) {
    if(a.w == b.w) return a.speed > b.speed;
    return a.w < b.w;
}

int main() {
    int w, speed;
    int cnt = 0;
    while(~scanf("%d%d", &w, &speed)) {
        mouse[cnt].id = cnt + 1, mouse[cnt].w = w, mouse[cnt].speed = speed;
        cnt ++;
    }

    sort(mouse, mouse + cnt, cmp);

    int ans = 0;
    for(int i = cnt - 1; i >= 0; i --) {
        f[i] = 1;
        for(int j = i + 1; j < cnt; j ++) {
            if(mouse[i].w < mouse[j].w && mouse[i].speed > mouse[j].speed) {
                f[i] = max(f[i], f[j] + 1);
            }
        }
        ans = max(ans, f[i]);
    }

    printf("%d\n", ans);

    for(int i = 0; i < cnt; i ++)
        if(f[i] == ans) {
        printf("%d\n", mouse[i].id);
        ans --;
    }

    return 0;
}

POJ 3186 Treats for the Cows

思路

区间DP, 逆着来, 当长度是1的时候,当它是最后一个选的

代码

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 2010;
int f[N][N];
int a[N];

int main() {
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++)
        scanf("%d", &a[i]);
    for(int len = 1; len <= n; len ++)
        for(int i = 1; i + len - 1 <= n; i ++) {
            int l = i, r = i + len - 1;
            f[l][r] = 1e8;
            if(l == r) f[l][r] = a[l] * n;
            else {
                f[l][r] = max(f[l + 1][r] + a[l] * (n - len + 1), f[l][r - 1] + a[r] *(n - len + 1));
            }
    }

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

HDU2859 Phalanx

思路

状态表示 f [ i ] [ j ] f[i][j] f[i][j]:所有以 i , j i,j i,j为左下角的对称子矩阵
属性:MAX

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 1005;

char s[N][N];
int f[N][N];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n;
    while(~scanf("%d", &n) && n) {
        memset(s, 0, sizeof s);
        memset(f, 0, sizeof f);
        for(int i = 1; i <= n; i ++)
            cin >> (s[i] + 1);
        for(int i = 1; i <= n; i ++) {
            f[i][n] = f[1][i] = 1;
        }
        int ans = 1;
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= n; j ++) {
                if(i == 1 || j == n) continue;
                int x = i, y = j;
                while(x >= 1 && j <= n && s[x][j] == s[i][y]) x --, y ++;
                int len = i - x;
                if(len >= f[i - 1][j + 1] + 1)
                    f[i][j] = f[i - 1][j + 1] + 1;
                else
                    f[i][j] = len;
                ans = max(ans, f[i][j]);
        }

        cout << ans << endl;
    }

    return 0;
}

POJ3616Milking Time

思路

状态表示 f [ i ] f[i] f[i]: 考虑前 i i i个区间的所有选法
属性: m a x max max
状态计算: f [ i ] = m a x ( f [ i ] , f [ j ] + p [ i ] . w ) ,    w h e n    p [ j ] . r + R < = p [ i ] . l f[i] = max(f[i], f[j] + p[i].w) ,\ \ when \ \ p[j].r + R <= p[i].l f[i]=max(f[i],f[j]+p[i].w),  when  p[j].r+R<=p[i].l

代码

#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 1010;
int f[N];
int n, m, R;


struct node {
    int l, r, w;
}p[N];

bool cmp(node a, node b) {
    return a.l < b.l;
}

int main() {
    while(~scanf("%d%d%d", &n, &m, &R)) {
        memset(f, 0, sizeof f);
        int cnt = 0;
        for(int i = 0; i < m; i ++) {
            int l, r, w;
            scanf("%d%d%d", &l, &r, &w);
            p[cnt].l = l, p[cnt].r = r, p[cnt].w = w, cnt ++;
        }
        sort(p, p + cnt, cmp);
        int ans = 0;
        for(int i = 0; i < m; i ++){
            f[i] = p[i].w;
            for(int j = 0; j < i; j ++){
                if(p[j].r + R <= p[i].l)
                    f[i] = max(f[i], f[j] + p[i].w);
            }
            ans = max(ans, f[i]);
        }

        printf("%d\n", ans);
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值