2017暑假集训 div1 DP(2)

poj 3186

题意:给一串数字,每次可以从最左端和最右端拿去一个数字,得到的价值是本身数字乘以拿去的次序

做法:区间DP 每次枚举长度然后枚举起点,从左右两端开始转移即可DP[I][J]代表I是起点J 是终点的最大值。
#include <iostream>
#include <algorithm>
#include <string.h>
#include <stdio.h>
#include <queue>
using namespace std;
int n;
int a[3000];
int dp[3000][3000];

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

    memset(dp,0,sizeof(dp));
    for(int i=1;i<=n;++i) dp[i][i]=a[i]*n;
    for(int len=1;len<=n-1;++len)
    {
        for(int s=1;s+len<=n;++s)
        {
            dp[s][s+len]=max(dp[s][s+len],dp[s+1][s+len]+a[s]*(n-len));
            dp[s][s+len]=max(dp[s][s+len],dp[s][s+len-1]+a[s+len]*(n-len));
        }
    }
    printf("%d\n",dp[1][n]);
    return 0;
}

HDU 1079
简单线性DP。


HDU 2589
题意:给你一个n*n的矩阵,矩阵中只含有26个小写字母,求其中最大的对称矩阵的大小
做法:DP[I][j]是从(i,j)往左上角开始的最大对称矩阵,那么要求dp[I][j]只需要枚举新加的两条边是否对应相等,然后分两种情况即可

#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
using namespace std;
char str[1100][1100];
int dp[1100][1100];
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0) break;
        for(int i=0;i<n;++i) scanf("%s",str[i]);

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





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值