[kuangbin带你飞]专题十二 基础DP1

本文介绍了多个动态规划问题,包括Max Sum Plus Plus、Doing Homework、Super Jumping等,涵盖了不同的动态规划思想,如状态压缩、最长上升子序列、完全背包等。每个问题都提供了关键的转移方程和解题思路。
摘要由CSDN通过智能技术生成

A - Max Sum Plus Plus (HDU 1024)

题意:将n个数取m段且不相交,求m段数字和最大值;
dp[i][j]:前i个数字分成j段的最大值。
边界dp[0][0] = 0;
dp[i][j] = max(maxx[j - 1] + a[i], dp[i-1][j] + a[i]);//maxx[j]代表前i个数取j段的最大值。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
int a[maxn], dp[2][maxn], maxx[maxn];

int main()
{
//    freopen("in.txt", "r", stdin);
    std::ios::sync_with_stdio(false);
    int n, m;

    while(cin >> m >> n)
    {
        for(int i = 1; i <= n; i++)
            cin >> a[i];

        memset(dp, -0x3f3f3f3f, sizeof(dp));
        memset(maxx, -0x3f3f3f3f, sizeof(maxx));
        maxx[0] = 0; dp[0][0] = 0;

        for(int i = 1; i <= n; i++)
        {
            int ii = i & 1, tt = 1 - ii;

            for(int j = 1; j <= min(i, m); j++)
                dp[ii][j] = max(maxx[j - 1] + a[i], dp[tt][j] + a[i]);

            for(int j = 1; j <= min(i, m); j++)
                maxx[j] = max(maxx[j], dp[ii][j]);
        }

        cout << maxx[m] << '\n';
    }

    return 0;
}

B - Ignatius and the Princess IV(HDU - 1029)

水题

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
typedef long long ll;
map<ll, int> ma;
int main()
{
//    freopen("in.txt", "r", stdin);
    std::ios::sync_with_stdio(false);
    int n;

    while(cin >> n)
    {
        ll x, ans; ma.clear();

        for(int i = 1; i <= n; i++)
        {
            cin >> x; ma[x]++;

            if(ma[x] >= (n + 1) / 2) ans = x;
        }

        cout << ans << endl;
    }

    return 0;
}

C - Monkey and Banana (HDU - 1069)

题意:叠箱子,下面的长和宽严格比上面的大,问最高高度;
每个箱子可以旋转所以每种箱子都有6种放法。将它们放入一个结构体数组按长或者宽排序。
对于一个箱子i如果可以放在另一个箱子j上面则可以通过那个箱子转移 dp[i] = max(dp[i],dp[j]+j的长度);

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<map>
#define endl '\n'
using namespace std;
typedef long long ll;
struct node
{
    int a, b;
    int h;
    int now = 0;
} s[200];
int len;
void add(int a, int b, int c)
{
    s[len].a = a;
    s[len].b = b;
    s[len].now = 0;
    s[len++].h = c;
}
bool cmp(node a, node b)
{
    if(a.a != b.a)
        return a.a < b.a;
    else
        return a.b < b.b;
}
int main()
{
//    freopen("in.txt", "r", stdin);
    std::ios::sync_with_stdio(false);
    int n; int cas = 1;

    while(cin >> n)
    {
        if(n == 0) break;

        len = 0;

        for(int i = 1; i <= n; i++)
        {
            int a, b, c;
            cin >> a >> b >> c;
            add(a, b, c); add(b, a, c);
            add(a, c, b); add(c, a, b);
            add(c, b, a); add(b, c, a);
        }

        sort(s, s + len, cmp);
        int ans = 0;

        for(int i = 0; i < len - 1; i++)
        {
            for(int j = i + 1; j < len; j++)
            {
                if(s[i].b < s[j].b && s[i].a < s[j].a)
                {
                    s[j].now = max(s[j].now, s[i].now + s[i].h);
                    ans = max(ans, s[j].now + s[j].h);
                }
            }
        }

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

    return 0;
}

D - Doing Homework (HDU - 1074 )

题意:有n门课,每门课有截止时间和完成所需的时间,如果超过规定时间完成,每超过一天就会扣1分,问怎样安排做作业的顺序才能使得所扣的分最小
状态压缩+路径保留,每个状态由比它少一门课的状态转移,

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<stack>
#include<map>
using namespace std;
typedef long long ll;
struct node
{
    string str;
    int a, b;
} s[20];
const int maxn = 1 << 15 + 5;
int dp[maxn], pre[maxn], time[maxn];
int main()
{
//    freopen("in.txt", "r", stdin);
    std::ios::sync_with_stdio(false);
    int T; cin >> T;

    while(T--)
    {
        int n; cin >> n;

        for(int i = 1; i <= n; i++)
            cin >> s[i].str >> s[i].a >> s[i].b;

        memset(dp, 0x3f3f3f3f, sizeof(dp));
        memset(time, 0x3f3f3f3f, sizeof(time));
        dp[0] = 0;
        time[0] = 0;

        for(int i = 1; i < (1 << n); i++)
        {
            for(int j = 1; j <= n; j++)
            {
                int t = 1 << (j - 1);

                if(!(i & t)) continue;

                int soc = time[i - t] + s[j].b - s[j].a;

                if(soc < 0) soc = 0;

                if(dp[i] >= dp[i - t] + soc)
                {
                    dp[i] = dp[i - t] + soc;
                    time[i] = time[i - t] + s[j].b;
                    pre[i] = j;
                }
            }
        }

        cout << dp[(1 << n) - 1] << endl;

        stack<int> st;
        int now = (1 << n) - 1;

        while(now)
        {
            st.push(pre[now]);
            now -= (1 << (pre[now] - 1));
        }

        while(!st.empty())
        {
            cout << s[st.top()].str << endl;
            st.pop();
        }
    }

    return 0;
}

E - Super Jumping! Jumping! Jumping!( HDU - 1087)

最大的上升子序列+离散化

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<stack>
#include<map>
using namespace std;
typedef long long ll;
const int maxn = 1e3 + 50;
int s[maxn], b[maxn];
map<int, int> pos;
ll dp[maxn];
int main()
{
//    freopen("in.txt", "r", stdin);
    std::ios::sync_with_stdio(false);
    int n;

    while(cin >> n)
    {
        if(n == 0) break;

        memset(dp, 0, sizeof(dp));

        for(int i = 1; i <= n; i++) cin >> s[i], b[i] = s[i];

        sort(b + 1, b + 1 + n);
        int len = unique(b + 1, b + 1 + n) - b - 1;

        for(int i = 1; i <= len; i++)
            pos[b[i]] = i;

        ll ans = -1;

        for(int i = 1; i <= n; i++)
        {
            int p = pos[s[i]];
            ll maxx = 0;

            for(int j = 1; j < p; j++)
                maxx = max(maxx, dp[j]);

            dp[p] = max(dp[p], maxx + s[i] * 1ll);
            ans = max(ans, dp[p]);
        }

        cout << ans << endl;
    }

    return 0;
}

F - Piggy-Bank (HDU - 1114)

给出一个存钱罐的容量,给出n种硬币的价值p和重量w(注意:每种硬币可无限取)
如果存钱罐能够正好塞满,输出塞满存钱罐需要的最少的硬币价值。
完全背包

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<stack>
#include<map>
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 50;
int dp[maxn];
int main()
{
//    freopen("in.txt", "r", stdin);
    std::ios::sync_with_stdio(false);
    int T; cin >> T;

    while(T--)
    {
        int e, f; cin >> e >> f;
        int m = f - e;
        int n; cin >> n;
        memset(dp, 0x3f3f3f3f, sizeof(dp));
        int p, w;
        dp[0] = 0;

        for(int i = 1; i <= n; i++)
        {
            cin >> p >> w;

            for(int j = 0; j <= m - w; j++)
                dp[j + w] = min(dp[j + w], dp[j] + p);
        }

        if(dp[m] <= 5e8) printf("The minimum amount of money in the piggy-bank is %d.\n", dp[m]);
        else printf("This is impossible.\n");
    }

    return 0;
}

G - 免费馅饼 HDU - 1176

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<stack>
#include<map>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 50;
struct node
{
    int x, t;
} s[maxn];
int dp[maxn][11];
bool cmp(node a, node b)
{
    return a.t < b.t;
}
int now[20];
bool vis[maxn][20];
int main()
{
//    freopen("in.txt", "r", stdin);
    std::ios::sync_with_stdio(false);
    int n;

    while(~scanf("%d", &n))
    {
        if(n == 0) break;

        int T = 0;

        for(int i = 1; i <= n; i++)
        {
            scanf("%d%d", &s[i].x, &s[i].t);
            T = max(T, s[i].t);
        }

        sort(s + 1, s + 1 + n, cmp);
        memset(vis, false, sizeof(vis));
        memset(dp, 0, sizeof(dp));
        vis[0][5] = true;
        int cnt = 1;
        int ans = 0;

        for(int i = 1; i <= T; i++)
        {
            memset(now, 0, sizeof(now));

            while(s[cnt].t == i && cnt <= n)
                now[s[cnt++].x]++;

            for(int j = 0; j <= 10; j++)
            {
                int maxx = 0;

                if(j >= 1 && vis[i - 1][j - 1])
                {
                    maxx = max(maxx, dp[i - 1][j - 1] + now[j]);
                    vis[i][j] = true;
                }

                if(vis[i - 1][j + 1])
                {
                    maxx = max(maxx, dp[i - 1][j + 1] + now[j]);
                    vis[i][j] = true;
                }

                if(vis[i - 1][j])
                {
                    maxx = max(maxx, dp[i - 1][j] + now[j]);
                    vis[i][j] = true;
                }

                dp[i][j] = maxx;
                ans = max(ans, maxx);
            }
        }

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

    return 0;
}

H - Tickets HDU - 1260

水题

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<stack>
#include<map>
using namespace std;
typedef long long ll;
const int maxn = 2e3 + 50;
int a[maxn], b[maxn];
int dp[maxn];
void func(int t)
{
//	printf("%d\n",t);
    int h = 8;
    int m = 0;
    int s = 0;
    int ju = 0;

    for(int i = t; i > 0; i--)
    {
        s++;

        if(s >= 60)
        {
            m++;
            s -= 60;
        }

        if(m >= 60)
        {
            h++;
            m -= 60;
        }

        if(h == 12) ju = (ju + 1) % 2;

        if(h > 12)
            h -= 12;
    }

    printf("%02d:%02d:%02d ", h, m, s);

    if(ju == 1)printf("pm\n");
    else printf("am\n");
}
int main()
{
//    freopen("in.txt", "r", stdin);
    int T; cin >> T;

    while(T--)
    {
        int n; cin >> n;

        for(int i = 1; i <= n; i++) cin >> a[i];

        for(int i = 1; i < n; i++) cin >> b[i];

        memset(dp, 0x3f3f3f3f, sizeof(dp));
        dp[1] = a[1];
        dp[0] = 0;

        for(int i = 2; i <= n; i++)
            dp[i] = min(dp[i - 2] + b[i - 1], dp[i - 1] + a[i]);

        func(dp[n]);
    }

    return 0;
}

I - 最少拦截系统 HDU - 1257

贪心+lower_bound

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<stack>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
vector<int> ve;
int main()
{
//    freopen("in.txt", "r", stdin);
    int n;

    while(cin >> n)
    {
        ve.clear();
        int ans = 1;
        int x; cin >> x;
        ve.push_back(x);
        vector<int>::iterator it;

        for(int i = 2; i <= n; i++)
        {
            cin >> x;

            if(ve.back() < x)
            {
                ans++;
                ve.push_back(x);
            }

            else
            {
                it = lower_bound(ve.begin(), ve.end(), x);
                ve.erase(it);
                ve.insert(it, x);
            }

        }

        cout << ans << endl;
    }

    return 0;
}

J - FatMouse’s Speed HDU - 1160

最长上升子序列变形

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<stack>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
struct node
{
    int w, s;
    int pos;
} a[1004];
bool cmp(node a, node b)
{
    return a.s > b.s;
}
int dp[1005];
int pre[1005];
int main()
{
//    freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false);
    int n = 0;
    int w, s;

    while(cin >> w >> s)
    {
        a[++n].s = s;
        a[n].w = w;
        a[n].pos = n;
    }

    sort(a + 1, a + 1 + n, cmp);
    dp[0] = 0;
    int ans = 0;
    int ansi;
    dp[1] = 1;

    for(int i = 2; i <= n; i++)
    {
        int maxx = 0;
        int p;

        for(int j = 1; a[j].s > a[i].s; j++)
        {
            if(a[j].w < a[i].w)
            {
                if(maxx <= dp[j])
                {
                    maxx = dp[j];
                    p = j;
                }
            }
        }

        dp[i] = maxx + 1;
        pre[i] = p;

        if(ans <= dp[i])
        {
            ans = dp[i];
            ansi = i;
        }
    }

    stack<int> st;
    cout << ans << endl;

    while(ans--)
    {
        st.push(a[ansi].pos);
        ansi = pre[ansi];
    }

    while(!st.empty())
    {
        cout << st.top() << endl;
        st.pop();
    }

    return 0;
}

K - Jury Compromise POJ - 1015

难题!
题意:在遥远的国家佛罗布尼亚,嫌犯是否有罪,须由陪审团决定。陪审团是由法官从公众中挑选的。先随机挑选n个人作为陪审团的候选人,然后再从这n个人中选m人组成陪审团。选m人的办法是:
控方和辩方会根据对候选人的喜欢程度,给所有候选人打分,分值从0到20。为了公平起见,法官选出陪审团的原则是:选出的m个人,必须满足辩方总分和控方总分的差的绝对值最小。如果有多种选择方案的辩方总分和控方总分的之差的绝对值相同,那么选辩控双方总分之和最大的方案即可。

开三维的dp数组
dp[i][j][k]代表在第i个人时已经选了j个人分差为k的情况下最大的总分;
因为分差可以是负数所以每个都加上400是它变成正数就能用数组保存了。能够想出来dp的结构的话转移就比较容易了。
dp[i][j][k] = max(dp[i-1][j][k],dp[i-1][j-1][k-差值]+d[i]+p[i]);
另一个难点就是路径保留了。pre数组保存当前状态是通过选择哪个陪审团而来的。
最后尤其要注意看清输出的格式。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<stack>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
int dp[202][21][805], pre[202][21][805];
int d[300], p[300], cha[300];
int main()
{
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt","w",stdout);
    int cas = 1;
    int n, m;

    while(~scanf("%d%d", &n, &m))
    {
        if(n == 0) break;

        for(int i = 1; i <= n; i++)
        {
            scanf("%d%d", &d[i], &p[i]);
            cha[i] = d[i] - p[i];
        }

//        bianjie
//        memset(pre, 0, sizeof(pre));
        memset(dp, -0x3f3f3f3f, sizeof(dp));

        for(int i = 0; i <= n; i++)
            dp[i][0][400] = 0;

        for(int i = 1; i <= n; i++)
        {
            int ch = cha[i];

            for(int j = min(m, i); j >= 1; j--)
            {
                for(int k = -400; k <= 400; k++)
                {
//                    dp[j][k+ch] = dp[j-1][k] + d[i]+p[i];
                    if(k + ch + 400 < 0 || k + ch + 400 > 800) continue;

                    dp[i][j][k + ch + 400] = dp[i - 1][j][k + ch + 400];
                    pre[i][j][k + ch + 400] = pre[i - 1][j][k + ch + 400];

                    int t = dp[i - 1][j - 1][k + 400] + d[i] + p[i];

                    if(t > dp[i][j][k + ch + 400])
                    {
                        dp[i][j][k + ch + 400] = t;
                        pre[i][j][k + ch + 400] = i;
                    }
                }

            }
        }

        printf("Jury #%d\n", cas++);
        int D = 0, P = 0;
        int ansi;

        for(int i = 0; i <= 400; i++)
        {
//            cout<<i-400<<" "<<dp[m][i]<<endl;
            if(dp[n][m][400 - i] >= 0 || dp[n][m][400 + i] >= 0)
            {
                ansi = dp[n][m][400 - i] > dp[n][m][400 + i] ? 400 - i : 400 + i;
                break;
            }
        }

        vector<int> ans;

        while(m)
        {
            int t = pre[n][m][ansi];
            ans.push_back(t);
//            cout<<pre[m][ansi]<<endl;
            D += d[t]; P += p[t];
            ansi -= cha[t];
            m--;
            n = pre[t - 1][m][ansi];
        }

        sort(ans.begin(), ans.end());
        printf("Best jury has value %d for prosecution and value %d for defence:\n", D, P);

        for(int i = 0; i < ans.size(); i++)
            printf(" %d", ans[i]);

        printf("\n\n");
    }

    return 0;
}

L - Common Subsequence POJ - 1458

水题

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<stack>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
int dp[8000][8000];
char a[10000], b[10000];
int main()
{
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);

    while(~scanf("%s%s", a + 1, b + 1))
    {
        int n = strlen(a + 1);
        int m = strlen(b + 1);

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

        for(int i = 0; i <= m; i++) dp[0][i] = 0;

        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
            {
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);

                if(a[i] == b[j]) dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1);
            }

        printf("%d\n", dp[n][m]);
    }

    return 0;
}

M - Help Jimmy POJ - 1661

按板子高度先排序,不用管高度,因为永远是一个固定的。
dp[i][0]代表到第i块板子的左端需要的时间。dp[i][1]右边。
可以从下往上dp也可以从上往下。
图论的Dijkstra也能写这道题。。。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<stack>
#include<map>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 5;
struct node
{
    int l, r, h;
} s[maxn];
bool cmp(node a, node b)
{
    return a.h > b.h;
}
int dp[maxn][2];
int main()
{
//    freopen("in.txt", "r", stdin);
    int T; scanf("%d", &T);

    while(T--)
    {
        int n, sx, sy, maxh;
        scanf("%d%d%d%d", &n, &sx, &sy, &maxh);

        for(int i = 1; i <= n; i++)
            scanf("%d%d%d", &s[i].l, &s[i].r, &s[i].h);

        sort(s + 1, s + 1 + n, cmp);
        int st = 0;

        for(int i = 1; i <= n; i++) dp[i][0] = dp[i][1] = 0x3f3f3f3f;

        for(int i = 1; i <= n; i++)
        {
            if(s[i].l <= sx && s[i].r >= sx)
            {
                st = i;
                dp[i][0] = sx - s[i].l;
                dp[i][1] = s[i].r - sx;
                break;
            }
        }

        /*
            1
            3 8 17 20
            0 10 8
            0 10 13
            4 14 3
        */
        if(st == 0)
        {
            printf("%d\n", sy);
            continue;
        }

        int ans = 0x3f3f3f3f;

        for(int i = st; i <= n; i++)
        {
            bool okl = false, okr = false;

            for(int j = i + 1; j <= n; j++)
            {
//                cout<<dp[3][0]<<" "<<dp[3][1]<<endl;
                if(okl && okr) break;

                if(maxh < s[i].h - s[j].h) break;

                int L = s[i].l, R = s[i].r;

                if(!okl)
                    if(s[j].l <= L && s[j].r >= L)
                    {
                        okl = true;
                        dp[j][0] = min(dp[j][0], dp[i][0] + L - s[j].l);
                        dp[j][1] = min(dp[j][1], dp[i][0] + s[j].r - L);
                    }

                if(!okr)
                    if(s[j].l <= R && s[j].r >= R)
                    {
                        okr = true;
                        dp[j][0] = min(dp[j][0], dp[i][1] + R - s[j].l);
                        dp[j][1] = min(dp[j][1], dp[i][1] + s[j].r - R);
                    }
            }

            if(s[i].h <= maxh)
            {
                if(!okl)
                    ans = min(ans, dp[i][0] + sy);

                if(!okr)
                    ans = min(ans, dp[i][1] + sy);
            }
        }

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

    return 0;
}

N - Longest Ordered Subsequence POJ - 2533

水题

O - Treats for the Cows POJ - 3186

给一个数组a,每次可以取前面的或者后面的,第k次取的a[i]价值为v[i]*k,问总价值最大是多少。
dp[i][j]代表左边取i个右边取j个最大值。
dp[i][j] = max(dp[i - 1][j] + (i + j) * a[i], dp[i][j - 1] + (i + j) * a[n - j + 1]);

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<stack>
#include<map>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn = 2e3 + 5;
int dp[maxn][maxn];
int a[maxn];
int main()
{
//    freopen("in.txt", "r", stdin);
    int n; scanf("%d", &n);

    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);

    memset(dp, 0, sizeof(dp));
    dp[0][0] = 0;

    for(int i = 1; i <= n; i++)
        dp[i][0] = dp[i - 1][0] + i * (a[i]);

    for(int i = 1; i <= n; i++)
        dp[0][i] = dp[0][i - 1] + i * (a[n - i + 1]);

    int ans = max(dp[0][n], dp[n][0]);

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

            if(i + j == n) ans = max(ans, dp[i][j]);
        }
    }

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

P - FatMouse and Cheese HDU - 1078

老鼠每次最多垂直或者水平走k步停下来,停下的这个位置只能比上一个停留的位置大,并获取其价值,问最大能得到的价值

将每个点放入结构体按照价值排序。dp[i][j]为(i,j)点最高价值,从小到大遍历转移就行了。这个专题很多题都是类似的思路。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<stack>
#include<map>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn = 1e2 + 5;
struct node
{
    int x, y, w;
} s[10005];

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

int ma[maxn][maxn], dp[maxn][maxn], pos[maxn][maxn];
int main()
{
//    freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false);
    int n, k;

    while(cin >> n >> k)
    {
        if(n == -1) break;

        int cnt = 0;

        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
            {
                cin >> ma[i][j];
                s[++cnt].w = ma[i][j];
                s[cnt].x = i;
                s[cnt].y = j;
            }

        sort(s + 1, s + 1 + cnt, cmp);

        for(int i = 1; i <= cnt; i++)
            pos[s[i].x][s[i].y] = i;

        memset(dp, -0x3f3f3f3f, sizeof(dp));
        dp[1][1] = ma[1][1];
        int ans = -1;

        for(int i = 1; i <= cnt; i++)
        {
            int x = s[i].x;
            int y = s[i].y;

            if(dp[x][y] < 0) continue;

            for(int j = max(1, x - k); j <= min(x + k, n); j++)
            {
                if(s[pos[j][y]].w > s[i].w) dp[j][y] = max(dp[x][y] + ma[j][y], dp[j][y]);

                ans = max(ans, dp[j][y]);
            }

            for(int j = max(1, y - k); j <= min(y + k, n); j++)
            {
                if(s[pos[x][j]].w > s[i].w) dp[x][j] = max(dp[x][y] + ma[x][j], dp[x][j]);

                ans = max(ans, dp[x][j]);
            }
        }

        cout << ans << endl;
    }

    return 0;
}

Q - Phalanx HDU - 2859

求矩阵中子矩阵是关于左下角到右上角这条线对称的最大矩阵长度。

看了题解才会。。
dp[i][j]代表以(i,j)为左下角的最大矩阵。

                int x = i - 1, y = j + 1; int tem = 1;
                while(x >= 0 && y < n && ma[x][j] == ma[i][y])
                    x--, y++, tem++;

这样求出的tem就是i行往上j列往右的对称的长度,最后的dp[i][j] = min(tem, dp[i - 1][j + 1] + 1);

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<stack>
#include<map>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn = 1e3 + 5;
char ma[maxn][maxn];
int dp[maxn][maxn];
int main()
{
//    freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false);
    int n;

    while(cin >> n)
    {
        if(n == 0) break;

        for(int i = 0; i < n; i++) cin >> ma[i];

        int ans = 1;

        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < n; j++)
            {
                if(i == 0 || j == n - 1) {dp[i][j] = 1; continue;}

                int x = i - 1, y = j + 1; int tem = 1;

                while(x >= 0 && y < n && ma[x][j] == ma[i][y])
                    x--, y++, tem++;

                dp[i][j] = min(tem, dp[i - 1][j + 1] + 1);
                ans = max(ans, dp[i][j]);
            }
        }

        cout << ans << endl;
    }



    return 0;
}

R - Milking Time POJ - 3616

在一个农场里,在长度为N个时间可以挤奶,但只能挤M次,且每挤一次就要休息k分钟;
接下来给m组数据表示挤奶的时间与奶量求最大挤奶量

对于每个时间段的右边界先加上k。然后排序之后就是很简单的dp了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn = 1e3 + 5;
struct node
{
    int l, r, w;
} s[maxn];
bool cmp(node a, node b)
{
    return a.l < b.l;
}
int dp[maxn];
int main()
{
//    freopen("in.txt", "r", stdin);
    int n, m, k;
    scanf("%d%d%d", &n, &m, &k);

    for(int i = 1; i <= m; i++)
    {
        scanf("%d%d%d", &s[i].l, &s[i].r, &s[i].w);
        s[i].r += k;
    }

    s[0].r = -1;
    dp[0] = 0;
    sort(s + 1, s + 1 + m, cmp);
    int ans = 0;

    for(int i = 1; i <= m; i++)
    {
        int maxx = -1;

        for(int j = 0; j < i; j++)
        {
            if(s[j].r <= s[i].l && dp[j] > maxx)
                maxx = dp[j];
        }

        dp[i] = maxx + s[i].w;
        ans = max(ans, dp[i]);
    }

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

S - Making the Grade POJ - 3666

以前写过

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值