简单dp训练1

2017年08月13日 基础dp训练
1:
思路 最大子矩阵和的方法和最大字段和一样
可是我一开始还是不会。。

int a[mxn][mxn];
int sum[mxn][mxn];
int main(){
    int n;
    while(~sf("%d",&n)){
        mem(sum[0],0);
        for(int i=1;i<=n;++i){
            for(int j=1;j<=n;++j){
                sf("%d",&a[i][j]);
                sum[i][j]=sum[i-1][j]+a[i][j];
            }
        }
        int ans=-inf;
        for(int i=1;i<=n;++i){
            for(int j=i;j<=n;++j){
                int t=0;
                for(int k=1;k<=n;++k){
                    t+=sum[j][k]-sum[i][k];
                    ans=max(ans,t);
                    if(t<0)t=0;
                }
            }
        }
        pf("%d\n",ans);

    }
}

2:https://vjudge.net/contest/177552#problem/F
太坑了。。。
吧int 改为short 这样就不会爆内存。。。

char s[mxn];
short dp[mxn][mxn];
int main(){
    int n;
    while(~sf("%d",&n)){
        sf("%s",s+1);
        for(int i=1;i<=n;++i){
            for(int j=1;j<=n;++j){
                if(j<=i)dp[i][j]=0;
                else dp[i][j]=6000;
            }
        }
        for(int len=2;len<=n;++len){
            for(int i=1;i<=n-len+1;++i){
                int j=i+len-1;
                if(s[i]==s[j])dp[i][j]=dp[i+1][j-1];
                if(dp[i+1][j]+1<dp[i][j])dp[i][j]=dp[i+1][j]+1;
                if(dp[i][j-1]+1<dp[i][j])dp[i][j]=dp[i][j-1]+1;
                //dp[i][j]=min(dp[i][j],min(dp[i+1][j]+1,dp[i][j-1]+1));
                //pf("%d ",dp[i][j]);
            }
        }
        cout<<dp[1][n]<<'\n';
    }
}

还是学师兄的吧。。用的是吧 字符串反过来,变为求LCS。。。
然后用滚动数组优化

char s[mxn];
int dp[2][mxn];
int main(){
    int n;
    while(~sf("%d",&n)){
        sf("%s",s+1);
        mem(dp,0);
        for(int i=1;i<=n;++i){
            for(int j=1;j<=n;++j){
                dp[i%2][j]=max(dp[(i+1)%2][j],dp[i%2][j-1]);
                dp[i%2][j]=max(dp[i%2][j],dp[(i+1)%2][j-1]+(s[i]==s[n-j+1]));
            }
        }
        pf("%d\n",n-dp[n%2][n]);
    }
}

https://vjudge.net/contest/177552#problem/G
这个应该就只是一个很简单的LCS的变形啊。为什么我老是觉的空字符没法处理。。。

char s[mxn],t[mxn];
int dp[mxn][mxn];
int val[5][5]={
    5,-1,-2,-1,-3,
    -1,5,-3,-2,-4,
    -2,-3,5,-2,-2,
    -1,-2,-2,5,-1,
    -3,-4,-2,-1,-5
};
int f(char x){
    if(x=='A') return 0; if(x=='C') return 1; if(x=='G') return 2;
    if(x=='T') return 3;
    if(x==' ') return 4;
}
int main(){
    int T;sf("%d",&T);
    while(T--){
        int n,m;
        sf("%d %s",&n,s+1);sf("%d %s",&m,t+1);
        for(int i=1;i<=n;++i)
            dp[i][0]=dp[i-1][0]+val[f(s[i])][f(' ')];
        for(int i=1;i<=m;++i)
            dp[0][i]=dp[0][i-1]+val[f(t[i])][f(' ')];
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                dp[i][j]=max(dp[i-1][j]+val[f(s[i])][f(' ')],dp[i][j-1]+val[f(t[j])][f(' ')]);
                dp[i][j]=max(dp[i-1][j-1]+val[f(s[i])][f(t[j])],dp[i][j]);
            }
        }
        pf("%d\n",dp[n][m]);
    }
}

https://vjudge.net/contest/177552#problem/J
两边弄一下LIS。。
顺便回顾下那个二分法的LIS

double a[N];
double g1[N],g2[N];
int dp1[N],dp2[N];
int main(){
    int n;
    while(~sf("%d",&n)){
        mem(dp1,0);mem(dp2,0);
        for(int i=1;i<=n;++i)g1[i]=inf,g2[i]=inf;
        rep(i,1,n)sf("%lf",&a[i]);
        for(int i=1;i<=n;++i){
            int k=lower_bound(g1+1,g1+1+n,a[i])-g1;
            g1[k]=a[i];
            dp1[i]=k;
        }
        for(int i=n;i>=1;--i){
            int k=lower_bound(g2+1,g2+1+n,a[i])-g2;
            g2[k]=a[i];
            dp2[i]=k;
        }
        int ans=0;
        for(int i=1;i<=n;++i){
            for(int j=i+1;j<=n;++j){
                ans=max(ans,dp1[i]+dp2[j]);
            }
        }
        pf("%d\n",n-ans);
    }
}

这题做过,,这次差一点。。我不应该a[i]-=15,… 都不知道自己为什么要这样。。
http://blog.csdn.net/libin56842/article/details/21116143

int a[N],b[N];
int dp[25][M];
int main(){
    int n,m;
    while(~sf("%d%d",&n,&m)){
        rep(i,1,n){sf("%d",&a[i]);}
        rep(i,1,m){ sf("%d",&b[i]); }
        mem(dp,0);dp[0][8000]=1;
        for(int i=1;i<=m;++i){
            for(int j=0;j<=16000;++j){//平衡的地方。。
                if(dp[i-1][j]){//优化,有没有都可以,更快。
                    for(int k=1;k<=n;++k){
                        dp[i][j+b[i]*a[k]]+=dp[i-1][j];//注意方向
                    }
                }
            }
        }
        pf("%d\n",dp[m][8000]);
    }
}

https://vjudge.net/contest/177552#problem/O
不会。。没想都居然最后真的一个一个枚举当前的是不是合适的。

int a[N],c[N];
bool  dp[M];
int sum[M];
int main(){
    int n,m;
    while(~sf("%d%d",&n,&m)&&n+m){
        rep(i,1,n){sf("%d",&a[i]);}
        rep(i,1,n){sf("%d",&c[i]);}
        mem(dp,false);
        int ans=0;dp[0]=true;
        for(int i=1;i<=n;++i){
            mem(sum,0);
            for(int j=a[i];j<=m;++j){
                if(!dp[j]&&dp[j-a[i]]&&sum[j-a[i]]<c[i]){
                    dp[j]=true;
                    sum[j]=sum[j-a[i]]+1;
                    ++ans;
                }
            }
        }
        pf("%d\n",ans);
    }
}

https://vjudge.net/contest/177552#problem/P

不懂为何这题又是前推式才过了。。。我的有什么错误码。。。
可能我的题意没搞清楚,应该每一个组都要有一个花的。(还真的是。)

int a[N][N];
int dp[N][N];
int main(){
    int n,m;
    while(~sf("%d%d",&n,&m)){
        rep(i,1,n){ rep(j,1,m){ sf("%d",&a[i][j]); } }
        mem(dp,0);
        int ans=0;
        for(int i=1;i<=n;++i)dp[i][i]=dp[i-1][i-1]+a[i][i];
        for(int i=1;i<=n;++i){
            for(int j=i+1;j<=m;++j){
                dp[i][j]=max(dp[i][j-1],dp[i-1][j-1]+a[i][j]);
            }
        }
        /*
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                dp[i][j]=max(dp[i][j-1],max(dp[i][j],dp[i-1][j-1]+a[i][j]));
            }
        }*/
        pf("%d\n",dp[n][m]);
    }
}

https://vjudge.net/contest/177552#problem/Q

这题感觉枚举起点和终点会炸。。而且我的代码太丑了。。
看了师兄的。。挺好的。。

char t[N];
char word[N*2][N];
int len[N*2];
int dp[N];
int main(){
    int l,m;
    while(~sf("%d%d",&m,&l)){
        sf("%s",t+1);
        rep(i,1,m){sf("%s",word[i]+1);len[i]=strlen(word[i]+1);}
        for(int i=1;i<=l;++i){
            dp[i]=dp[i-1];
            for(int j=1;j<=m;++j){
                if(i>=len[j]&&word[j][len[j]]==t[i]){
                    int r=i-1,tmp=len[j]-1;
                    while(r&&tmp)if(word[j][tmp]==t[r--])--tmp;
                    if(!tmp&&dp[r]+len[j]>dp[i])dp[i]=dp[r]+len[j];
                }
            }
        }
        pf("%d\n",l-dp[l]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值