简单dp训练1

来源:互联网 发布:淘宝怎么测图 编辑:程序博客网 时间:2024/05/14 15:04

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]);    }}