DP简单题

The Triangle

题目传送:The Triangle

TLE代码(递归形式的DP):

#include <map>
#include <set>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <cstdio>
#include <cctype>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define INF 0x7fffffff
using namespace std;

const int maxn = 105;

int a[maxn][maxn];
int n;

int max_sum(int x, int y) {
    if(x == n) {
        return a[x][y];
    }
    else {
        return max(max_sum(x+1, y), max_sum(x+1, y+1)) + a[x][y];
    }
}

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

        cout << max_sum(1, 1) << endl;
    }
    return 0;
}

上面代码会超时,因为重复计算,复杂度高达O(2n),这里为了避免TLE,可以用一个辅助数组存储每一次计算出来的maxSum,因为记录了是否访问过,所以称为记忆化搜索,复杂度为O(n2)

AC代码(优化后的记忆化搜索):

#include <map>
#include <set>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <cstdio>
#include <cctype>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define INF 0x7fffffff
using namespace std;

const int maxn = 105;

int maxSum[maxn][maxn];//maxSum[i][j]代表从最底部到第i层第j个可以达到的最大值 
int a[maxn][maxn];
int n;

int max_sum(int x, int y) {
    if(maxSum[x][y] != -1) return maxSum[x][y];//优化,记忆化搜索 
    if(x == n) {
        maxSum[x][y] = a[x][y];
    }
    else {
        maxSum[x][y] = max(max_sum(x+1, y), max_sum(x+1, y+1)) + a[x][y];
    }
    return maxSum[x][y];
}

int main() {
    while(scanf("%d", &n) != EOF) {
        for(int i = 1; i <= n; i ++) {
            for(int j = 1; j <= i; j ++) {
                scanf("%d", &a[i][j]);
                maxSum[i][j] = -1;
            }
        }

        cout << max_sum(1, 1) << endl;
    }
    return 0;
}

上面还是递归形式的DP,我们可以进一步改为递推形式的DP

AC代码(改为递推形式的DP):

#include <map>
#include <set>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <cstdio>
#include <cctype>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define INF 0x7fffffff
using namespace std;

const int maxn = 105;

int a[maxn][maxn];
int maxSum[maxn][maxn];//maxSum[i][j]代表从最底部到第i层第j个可以达到的最大值 
int n;

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

        for(int i = 1; i <= n; i ++) {
            maxSum[n][i] = a[n][i];
        }

        for(int i = n-1; i >= 1; i --) {
            for(int j = 1; j <= i; j ++) {
                maxSum[i][j] = max(maxSum[i+1][j], maxSum[i+1][j+1]) + a[i][j];
            }
        }

        cout << maxSum[1][1] << endl;
    }
    return 0;
}

空间优化,其实可以不用maxSum数组的,因为a数组完全可以代替它

AC代码(优化了空间的DP):

#include <map>
#include <set>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <cstdio>
#include <cctype>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define INF 0x7fffffff
using namespace std;

const int maxn = 105;

int a[maxn][maxn];
int n;

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

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

        cout << a[1][1] << endl;
    }
    return 0;
}



最长上升子序列

题目传送:2757:最长上升子序列

AC代码(复杂度O(n2)):

#include <map>
#include <set>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <cstdio>
#include <cctype>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define INF 0x7fffffff
using namespace std;

const int maxn = 1005;

int n;
int a[maxn];
int maxLen[maxn];

int main() {
    while(scanf("%d", &n) != EOF) {
        for(int i = 0; i < n; i ++) {
            scanf("%d", &a[i]);
            maxLen[i] = 1;
        }

        int ans = 1;
        for(int i = 1; i < n; i ++) {
            for(int j = 0; j < i; j ++) {
                if(a[i] > a[j]) {
                    maxLen[i] = max(maxLen[i], maxLen[j] + 1);
                    ans = max(ans, maxLen[i]);
                }
            }
        }

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

AC代码(复杂度O(n*logn)):

#include <map>
#include <set>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <cstdio>
#include <cctype>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define INF 0x7fffffff
using namespace std;

const int maxn = 1005;

int n;
int a[maxn];
int g[maxn];

int main() {
    while(scanf("%d", &n) != EOF) {
        for(int i = 0; i < n; i ++) {
            scanf("%d", &a[i]);
        }

        for(int i = 0; i < n; i ++) g[i] = INF;

        int ans = 0;
        for(int i = 0; i < n; i ++) {
            int k = lower_bound(g, g + n, a[i]) - g;
            g[k] = a[i];
            ans = max(ans, k + 1);
        }

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



最长公共子序列

题目传送:Common Subsequence

AC代码(复杂度O(n*m)):

#include <map>
#include <set>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <cstdio>
#include <cctype>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define INF 0x7fffffff
using namespace std;

char s1[1005];
char s2[1005];

int dp[1005][1005];

int main() {
    while(scanf("%s %s", s1 + 1, s2 + 1) != EOF) {
        int len1 = strlen(s1 + 1);
        int len2 = strlen(s2 + 1);

        memset(dp, 0, sizeof(dp));
        for(int i = 1; i <= len1; i ++) {
            for(int j = 1; j <= len2; j ++) {
                if(s1[i] == s2[j]) {
                    dp[i][j] = dp[i-1][j-1] + 1;
                }
                else {
                    dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
                }
            }
        }
        printf("%d\n", dp[len1][len2]);
    }
    return 0;
}



神奇的口袋

题目传送:2755:神奇的口袋

AC代码:

#include <map>
#include <set>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <cstdio>
#include <cctype>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define INF 0x7fffffff
using namespace std;

int n;
int a[25];
int dp[45];//dp[i]表示有多少种不同的选择物品的方式可以达到i 

int main() {
    while(scanf("%d", &n) != EOF) {
        for(int i = 0; i < n; i ++) {
            scanf("%d", &a[i]);
        }
        memset(dp, 0, sizeof(dp));
        dp[0] = 1;//什么都不选的时候也是一种方式 
        for(int j = 0; j < n; j ++) {
            for(int i = 40; i >= 0; i --) {//为了保持当前状态只受上一状态影响,所以使用逆序 
                    dp[i] += dp[i - a[j]];//往前累加所以可能情况 
            }
        }
        printf("%d\n", dp[40]);
    }
    return 0;
}



0-1背包问题

题目传送:Charm Bracelet

AC代码:

#include <map>
#include <set>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <cstdio>
#include <cctype>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define INF 0x7fffffff
using namespace std;

int dp[13000];

int n, m;
int w[3500], d[3500];

int main() {
    while(scanf("%d %d", &n, &m) != EOF) {
        for(int i = 0; i < n; i ++) {
            scanf("%d %d", &w[i], &d[i]);
        }
        memset(dp, 0, sizeof(dp));
        for(int i = 0; i < n; i ++) {
            for(int j = m; j >= w[i]; j --) {
                dp[j] = max(dp[j], dp[j-w[i]]+d[i]);
            }
        }
        printf("%d\n", dp[m]);
    }
    return 0;
}



滑雪

题目传送:1088:滑雪

AC代码:

#include <map>
#include <set>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <cstdio>
#include <cctype>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define INF 0x7fffffff
using namespace std;

const int dx[] = {-1, 0, 1, 0};
const int dy[] = {0, 1, 0, -1};

int r, c;
int dp[105][105];
int h[105][105];

struct Pos {
    int x, y;
    int h;
    bool operator < (const Pos a)const {
        return h < a.h;
    }
}p[10005];
int cnt;

/*
bool operator < (const Pos a, const Pos b) {
    return a.h < b.h;
}
运算符重载函数,用于结构体的比较,可以写在结构体里面,也可以写外面,不过注意两种写法的不同 
*/

/* 
bool cmp(Pos a, Pos b) {
    return a.h < b.h;
}
也用于结构体的比较,不过调用sort函数时要改一下写法,本题可以写成sort(p, p + r * c, cmp);
*/

int main() {
    while(scanf("%d %d", &r, &c) != EOF) {
        cnt = 0;
        for(int i = 1; i <= r; i ++) {
            for(int j = 1; j <= c; j ++) {
                scanf("%d", &h[i][j]);
                p[cnt].x = i;
                p[cnt].y = j;
                p[cnt ++].h = h[i][j];
                dp[i][j] = 1;
            }
        }

        sort(p, p + r * c);

        int ans = 0;
        for(int i = 0; i < r * c; i ++) {
            int x = p[i].x;
            int y = p[i].y;
            for(int j = 0; j < 4; j ++) {
                int xx = x + dx[j];
                int yy = y + dy[j];
                if(xx >= 1 && xx <= r && yy >= 1 && yy <= c && h[xx][yy] < h[x][y]) {
                    dp[x][y] = max(dp[x][y], dp[xx][yy] + 1);
                }
            }
            ans = max(ans, dp[x][y]);
        }

        printf("%d\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值