dp专场的蒟蒻题解

Posted cyq123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了dp专场的蒟蒻题解相关的知识,希望对你有一定的参考价值。

前言:一直想练练dp,正好衣神弄了个训练赛。。上次看cgold大佬的题解心血来潮所以自己试着写了第一次题解。。可惜本蒟蒻的能力太差有两道题做不太出,只好搬运学习其它大佬的题解了。。

a题

https://vjudge.net/contest/355951#problem/A

这题做题的过程十分痛苦

我又双叒叕看错题意了。。

以为是必须在对角线上

其实是随便n*n的都行。。

大概思路是从一个角开始更新,统计左边和上边相同的长度

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#include <sstream>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define Mod 1000000007
#define eps 1e-6
#define ll long long
#define INF 0x3f3f3f3f 
#define MEM(x,y) memset(x,y,sizeof(x))
#define Maxn 100005
#define P pair<int,int>
using namespace std;
char a[1005][1005];
int dp[1005][1005];
int n;


int main()
{
    int n, ans;
    while (cin>>n , n)
    {
        ans = 1;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
            {
                cin >> a[j][i];
            }
        for (int i = 0; i < n; i++)
        {
            for (int j = n - 1; j >= 0; j--)
            {
                dp[i][j] = 1;
                if (i == 0 || j == n - 1) continue;
                int q = dp[i - 1][j + 1];
                for (int k = 1; k <= q; k++)
                {
                    if (a[i - k][j] == a[i][j + k]) dp[i][j]++;
                    else break;
                }
                ans = max(ans, dp[i][j]);
            }
        }
        printf("%d
", ans);
    }
    return 0;
}

 

 b题

https://vjudge.net/contest/355951#problem/B

这题有点难。。

蒟蒻直接下线。。。

那就学下网上大佬的方法吧

dp(j, k)表示,取j 个候选人,使其辩控差为k 的所有方案中,辩控和最大的那个方案(该方案称为“方案dp(j, k)”)的辩控和

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
using namespace std;

#define N 220
#define met(a, b) memset(a, b, sizeof(a))
#define INF 0xffffff
const long long  Max = 2000000000;
typedef long long LL;

int D[N], P[N];
int dp[30][1000];  ///dp[i][k]代表选 i 个人, 辩控差为 k 的辩控和最大
int pre[30][1000]; ///pre[i][k] 存的是它是上次选的人
int Answer[N];     ///记录选中的这 m 个人的编号

int main()
{
    int n, m, iCase=1;

    while(scanf("%d%d", &n, &m), n||m)
    {
        int i, j, k, Min, t1, t2;

        met(D, 0);
        met(P, 0);
        met(dp, -1);
        met(pre, 0);
        met(Answer, 0);

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

        Min = m*20; ///它的辩控差最大为 m*20  
        dp[0][Min] = 0;  ///起始状态要先置为 0


        /// k 的最大取值范围是[-Min, Min], 但是数组不能表示负数, 因此将数组向右平移 Min,得到[0, 2*Min]
        for(i=0; i<=m; i++)
        {
            for(k=0; k<=Min*2; k++)
            {
                if(dp[i][k]==-1) continue;  ///如果存在,接着找 dp[i][k] 的下一个状态

                for(j=1; j<=n; j++)
                {
                        if(dp[i+1][k+D[j]-P[j]] < dp[i][k]+D[j]+P[j])
                        {
                            t1=i, t2=k;

                            while(t1>0 && pre[t1][t2]!=j)  
                            {
                                t2 -= D[pre[t1][t2]] - P[pre[t1][t2]];
                                t1 --;
                            }
                            if(t1==0)   ///当 t1 为 0 时,编号为 j 这个人在之前没有被选中过
                            {
                                dp[i+1][k+D[j]-P[j]] = dp[i][k] + D[j] + P[j];
                                pre[i+1][k+D[j]-P[j]] = j;
                            }
                        }

                }
            }
        }

        int ff = Min;
        int num = 0, sum1=0, sum2=0;

        ///要选辩控差最小的,所求的 num 便是选 m 个人辩控差最小的 
        while(dp[m][ff-num]==-1 && dp[m][ff+num]==-1) num++;

        if(dp[m][ff-num]>dp[m][ff+num]) t2 = ff-num;
        else    t2 = ff+num;

        t1 = m;

        for(i=1; i<=m; i++)
        {
            Answer[i] = pre[t1][t2];

            sum1 += D[Answer[i]];
            sum2 += P[Answer[i]];

            t1--;
            t2 -= D[Answer[i]] - P[Answer[i]];
        }

        printf("Jury #%d
", iCase++);
        printf("Best jury has value %d for prosecution and value %d for defence:
", sum1, sum2);


        sort(Answer+1, Answer+1+m);

        for(i=1; i<=m; i++)
            printf(" %d", Answer[i]);

        printf("

");
    }
    return 0;
}

  

以上是关于dp专场的蒟蒻题解的主要内容,如果未能解决你的问题,请参考以下文章

博弈专场~~太好玩了

写在前面的话

坑——待填?!

题解 P1469 找筷子

关于ztc.

P1057 传球游戏