zoukankan      html  css  js  c++  java
  • 压缩维度oj P1173+P1174+P1164

    今天在洛谷上刷dp,忽然冒出一道求最大字段和的问题,然后忘了瞬间忘了这是dp,几分钟一个贪心出来了成功ac,忽然想起自己在作dp,于是乖乖刷dp。

    这个可能很多人都会但是今天有4种解法哦,本人只尝试了3种解法。

    NO.1:明显一个贪心一个sum求当前的累加和如果小于0就清零,继续累加并不断去max即可。

    #include<iostream>
    #include<cstdio>
    #include<map>
    #include<vector>
    #include<iomanip>
    #include<cmath>
    #include<ctime>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<queue>
    #include<stack>
    using namespace std;
    inline long long read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int n;
    int a[200009];
    int ans=0;
    int maxx=-1111111;
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();
        for(int i=1;i<=n;i++)a[i]=read();
        for(int i=1;i<=n;i++)
        {
            ans+=a[i];
            if(ans>maxx)
            {
                maxx=ans;
            }
            if(ans<0)
                ans=0;
        }
        printf("%d
    ",maxx);
        return 0;
    }
    View Code

    NO.2:说是要练dp嘛,然后点开题解看dalao们的dp,f[i]=max(f[i-1],a[i]);这样最大值在f[i]之中,最后找max即可。

    #include<iostream>
    #include<cstdio>
    #include<map>
    #include<vector>
    #include<iomanip>
    #include<cmath>
    #include<ctime>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<queue>
    #include<stack>
    using namespace std;
    inline long long read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int n;
    int a[200009];
    int f[200009];
    int ans=-1111111;
    int main()
    {
    //    freopen("1.in","r",stdin);
        n=read();
        for(int i=1;i<=n;i++)
        {
            a[i]=read();
            f[i]=max(f[i-1]+a[i],a[i]);
            ans=max(f[i],ans);
        }
        cout<<ans<<endl;
        return 0;
    }
    View Code

    NO.3:题解之中有一个分治的想法,十分巧妙的把所有情况递归出来从而求解。在每一个区间之中取max即可。

    #include<iostream>
    #include<cstdio>
    #include<map>
    #include<vector>
    #include<iomanip>
    #include<cmath>
    #include<ctime>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<queue>
    #include<stack>
    using namespace std;
    inline long long read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    const int maxn=-1111111;
    int n;
    int a[200009];
    int bwy(int x,int y)
    {
        if(x==y)return a[x];
        int mid=(x+y)>>1;
        int maxx=maxn,maxx1=maxn,sum=0;
        for(int i=mid;i>=x;i--){sum+=a[i];maxx=max(maxx,sum);}sum=0;
        for(int i=mid+1;i<=y;i++){sum+=a[i];maxx1=max(maxx1,sum);}
        return max(max(bwy(x,mid),bwy(mid+1,y)),maxx+maxx1);
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();
        for(int i=1;i<=n;i++)a[i]=read();
        printf("%d
    ",bwy(1,n));
        return 0;
    }
    View Code

    这个就比较难理解了,要多看看。

    No.4:有大神用的是线段树来维护,tql,我不想打线段树代码就没有了。。。

    下面回到了本校oj看起来以前过得题想要再想想。求最大连续子矩阵累加和,这个就要压缩维度了。

    仔细想想,我可以先把每一列的前缀和全部求出来进行维度的压缩,然用一个一维数组来表示第几列从第i行到第j行的累加,十分巧妙的思想,我想了十几分钟才搞懂。这样的话就可以便利到每一个矩阵了,十分巧妙!!!

    #include<iostream>
    #include<cstdio>
    #include<map>
    #include<vector>
    #include<iomanip>
    #include<cmath>
    #include<ctime>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<queue>
    #include<stack>
    using namespace std;
    inline long long read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    const int maxn=505;
    int n,a[maxn][maxn],tmp[maxn],maxx=-1100000,ans=0;
    int main()
    {
        freopen("1.in","r",stdin);
        n=read();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                maxx=read();
                a[i][j]=a[i-1][j]+maxx;//前缀和
            }
        maxx=-1100000;
        for(int i=1;i<=n;i++)
        {
            for(int j=i;j<=n;j++)
            {
                ans=0;//注意便利下一个矩阵的时候ans要清零。
                for(int k=1;k<=n;k++)
                {
                    tmp[k]=a[j][k]-a[i-1][k];
                    ans+=tmp[k];
                    if(ans>maxx)maxx=ans;
                    if(ans<0)ans=0;
                }
            }
        }
        printf("%d
    ",maxx);
        return 0;
    }
    View Code

    然后还有很难的三维压缩qwq真不想写。。。

    三维的压缩,但首先要看懂题。

    看着学长的代码自慢慢干,发现书上的方法并不是很优,还不如和第二题一样进行压缩。

    a[i][j][k]+=a[i-1][j][k];压缩高度——c[k][u]=a[j][k][u]-a[i-1][k][u];再取任意宽度和长度的立方体块压到一个二维数组之中实现任意立方体小块的拿取,

    这样就可以了,c[k][u]+=c[k][u-1];压缩宽度这样就和上一题一样开始压缩二维数组,取任意矩阵的和。b[x]=c[x][u]-c[x][k-1];——这样压缩到一维的数组里面取任意的矩阵然后用求最大字段和就行了。是很难理解的表示不想手动模拟一遍。。。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<map>
    #include<vector>
    #include<iomanip>
    #include<cmath>
    #include<ctime>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<queue>
    #include<stack>
    using namespace std;
    inline long long read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int a[101][101][101],c[101][101],b[101],ans,maxx=-1000000;
    int n,h,m;
    int main()
    {
        //freopen("1.in","r",stdin);
        h=read();m=read();n=read();
        for(int i=1;i<=h;i++)for(int j=1;j<=m;j++)for(int k=1;k<=n;k++)
        a[i][j][k]=read(),a[i][j][k]+=a[i-1][j][k];
        for(int i=1;i<=h;i++)for(int j=i;j<=h;j++)
        {
            for(int k=1;k<=m;k++)for(int u=1;u<=n;u++)
            {
                c[k][u]=a[j][k][u]-a[i-1][k][u];
                c[k][u]+=c[k][u-1];
            }
            for(int k=1;k<=n;k++)for(int u=k;u<=n;u++)
            {
                ans=0;
                for(int x=1;x<=m;x++)
                {    
                    b[x]=c[x][u]-c[x][k-1];
                    ans+=b[x];
                    if(ans>maxx)maxx=ans;
                    if(ans<0)ans=0;
                }
            }
        }
        printf("%d
    ",maxx);
        return 0;
    }
    View Code

    大功告成啦。。。

    如果你的青春感到迷茫,那就对了,因为谁的青春不迷茫。

    b[x]=c[x][u]-c[x][k-1];

  • 相关阅读:
    Visifire正式版(v1.1)发布
    [转]PSP机能强大!已能模拟运行WINDOWS系统?
    在Silverlight+WCF中应用以角色为基础的安全模式(一)基础篇之角色为基础的安全模式简介 Virus
    C#的加密解密算法,包括Silverlight的MD5算法 Virus
    MMORPG programming in Silverlight Tutorial (10)Implement the sprite’s 2D animation (Part IV)
    Game Script: Rescue Bill Gates
    MMORPG programming in Silverlight Tutorial (9)KeyFrame Animation
    MMORPG programming in Silverlight Tutorial (5)Implement the sprite’s 2D animation (Part II)
    MMORPG programming in Silverlight Tutorial (7)Perfect animation
    MMORPG programming in Silverlight Tutorial (3)Animate the object (Part III)
  • 原文地址:https://www.cnblogs.com/chdy/p/9741603.html
Copyright © 2011-2022 走看看