区间dp

http://acm.hdu.edu.cn/showproblem.php?pid=4632

 

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1009;
char str[maxn];
int dp[maxn][maxn];
char sum[26][maxn];
int Q(int l,int r){
    if(l>r) return 0;
    return dp[l][r];
}
const int mod = 10007;
void add(int &k,int val){
    k+=val;
    if(k>=mod) k-=mod;
    if(k<0) k+=mod;
}
int main()
{
    int cas = 1;
    int T;scanf("%d",&T);
    while(T--){
        scanf("%s",str+1);
        memset(dp,0,sizeof(dp));
        int len = strlen(str+1);
        for(int k=1;k<=len;k++){
            for(int i=1;i+k-1<=len;i++){
                int l = i,r = i+k-1;
                add(dp[l][r],Q(l,r-1));
                add(dp[l][r],Q(l+1,r));
                add(dp[l][r],-Q(l+1,r-1));
                if(str[l]==str[r]) {
                    add(dp[l][r],1);
                    add(dp[l][r],Q(l+1,r-1));
                }

            }
        }
        printf("Case %d: ",cas++);
        printf("%d\n",dp[1][len]);
    }
    return 0;
}

  http://acm.hdu.edu.cn/showproblem.php?pid=4745

这题我企图倍增后逆序求两个的最长公共子序列再骚搞,然而是个错的,不能用dp[i][j]求区间10到i,10到j的最长子序列

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2009;
int a[maxn];
int dp[maxn][maxn];
int main()
{
    int n;
    while(scanf("%d",&n)){
        if(n==0) break;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            a[i+n] = a[i];
        }
        for(int k=1;k<=2*n;k++){
            for(int i=1;i<=2*n;i++){

                int l=i,r = i+k-1;
                dp[l][r] = 0;
                if(l==r)
                    dp[l][r]++;
                else if(a[l]==a[r])
                dp[l][r] = dp[l+1][r-1]+2;
                dp[l][r] = max(dp[l][r],dp[l+1][r]);
                dp[l][r] = max(dp[l][r],dp[l][r-1]);
            }
        }
        int ans = 0;
        for(int i=1;i<=2*n;i++){
            if(i+n-1<=2*n)
            ans = max(ans,dp[i][i+n-1]);
            if(i+n-2<=2*n)
            ans = max(ans,dp[i][i+n-2]+1);
        }
        printf("%d\n",ans);
    }

    return 0;
}

  http://hihocoder.com/problemset/problem/1636

因为有连续性这个条件所以枚举可以省掉一维,本来想k堆转移的时候还要考虑左边1,2,3,4.。。。k-1堆,右边k-1,k-2,...1堆的枚举,实际上不用,因为总有最左的一堆,只要枚举最左堆所在的区间就行了

#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int maxn = 109;
int a[maxn];
const int inf = 0x3f3f3f3f;
int sum[maxn];
int dp[maxn][maxn][maxn];
int main()
{
    int n,l,r;
    while(~scanf("%d%d%d",&n,&l,&r)){
        memset(dp,0x3f,sizeof(dp));
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            sum[i] = sum[i-1]+a[i];
        }
        for(int k=1;k<=n;k++){
            for(int i=1;i+k-1<=n;i++){
                int ll = i,rr = i+k-1;
                if(ll==rr) dp[ll][rr][1] = 0;
                else
                dp[ll][rr][1] = (k<=r && k>=l)?(sum[rr]-sum[ll-1]):inf;
                for(int j=2;j<=k;j++){
                    if(rr-ll+1==j){
                        dp[ll][rr][j] = 0;
                        continue;
                    }
                    for(int z = ll;z+1<=rr;z++){
                        dp[ll][rr][j] = min(dp[ll][rr][j],dp[ll][z][1]+dp[z+1][rr][j-1]);
                    }
                }
                for(int j=2;j<=k;j++)if(j<=r && j>=l){
                    dp[ll][rr][1] = min(dp[ll][rr][1],dp[ll][rr][j]+sum[rr]-sum[ll-1]);
                }
            }
        }
        int ans = dp[1][n][1];
        printf("%d\n",ans==inf?0:ans);
    }
    return 0;
}

  

posted @ 2018-04-15 15:34  tjucxz  阅读(154)  评论(0编辑  收藏  举报