• 矩阵取数游戏


    题目描述 Description

    【问题描述】
    帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m 的矩阵,矩阵中的每个元素aij均
    为非负整数。游戏规则如下:
    1. 每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有元素;
    2. 每次取走的各个元素只能是该元素所在行的行首或行尾;
    3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分= 被取走的元素值*2i,
    其中i 表示第i 次取数(从1 开始编号);
    4. 游戏结束总得分为m次取数得分之和。
    帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。

    输入描述 Input Description

    第1行为两个用空格隔开的整数n和m。
    第2~n+1 行为n*m矩阵,其中每行有m个用单个空格隔开的非负整数。

    输出描述 Output Description

    输出 仅包含1 行,为一个整数,即输入矩阵取数后的最大得分。

    样例输入 Sample Input

    2 3
    1 2 3
    3 4 2

    样例输出 Sample Output

    82

    数据范围及提示 Data Size & Hint

    样例解释

    第 1 次:第1 行取行首元素,第2 行取行尾元素,本次得分为1*21+2*21=6
    第2 次:两行均取行首元素,本次得分为2*22+3*22=20
    第3 次:得分为3*23+4*23=56。总得分为6+20+56=82

    【限制】
    60%的数据满足:1<=n, m<=30, 答案不超过1016
    100%的数据满足:1<=n, m<=80, 0<=aij<=1000

    挺水的一道DP,每一行各自取数对其他都没影响,所以对每一行都算一次最大值,然后加起来就是答案了
    dp[i][j],i表示左边取了几位,j表示右边取了几位。所以dp[i][j]=max(dp[i-1][j]+num[i]*pow(2,i+j),dp[i][j-1]+num[m-j+1]*pow(2,i+j))
    就是要注意高精度了= =,高精度直接拉的模板
    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    typedef double db;
    #define X first
    #define Y second
    #define mp(a,b) make_pair(a,b)
    #define pb push_back
    #define sd(x) scanf("%d",&(x))
    #define Pi acos(-1.0)
    #define sf(x) scanf("%lf",&(x))
    #define ss(x) scanf("%s",(x))
    #define maxn 50005
    //const int inf=0x3f3f3f3f;
    //const ll mod=1000000007;
    #define MAXN 9999
    #define MAXSIZE 1010
    #define DLEN 4
    class BigNum
    {
    private:
        int a[500]; //可以控制大数的位数
        int len;
    public:
        BigNum()
        {
            len=1;    //构造函数
            memset(a,0,sizeof(a));
        }
        BigNum(const int); //将一个int类型的变量转化成大数
        BigNum(const char*); //将一个字符串类型的变量转化为大数
        BigNum(const BigNum &); //拷贝构造函数
        BigNum &operator=(const BigNum &); //重载赋值运算符,大数之间进行赋值运算
        friend istream& operator>>(istream&,BigNum&); //重载输入运算符
        friend ostream& operator<<(ostream&,BigNum&); //重载输出运算符
        BigNum operator+(const BigNum &)const; //重载加法运算符,两个大数之间的相加运算
        BigNum operator-(const BigNum &)const; //重载减法运算符,两个大数之间的相减运算
        BigNum operator*(const BigNum &)const; //重载乘法运算符,两个大数之间的相乘运算
        BigNum operator/(const int &)const; //重载除法运算符,大数对一个整数进行相除
        BigNum operator^(const int &)const; //大数的n次方运算
        int operator%(const int &)const; //大数对一个int类型的变量进行取模运算
        bool operator>(const BigNum &T)const; //大数和另一个大数的大小比较
        bool operator>(const int &t)const; //大数和一个int类型的变量的大小比较
        void print(); //输出大数
    };
    BigNum::BigNum(const int b) //将一个int类型的变量转化为大数
    {
        int c,d=b;
        len=0;
        memset(a,0,sizeof(a));
        while(d>MAXN)
        {
            c=d-(d/(MAXN+1))*(MAXN+1);
            d=d/(MAXN+1);
            a[len++]=c;
        }
        a[len++]=d;
    }
    BigNum::BigNum(const char *s) //将一个字符串类型的变量转化为大数
    {
        int t,k,index,L,i;
        memset(a,0,sizeof(a));
        L=strlen(s);
        len=L/DLEN;
        if(L%DLEN)len++;
        index=0;
        for(i=L-1; i>=0; i-=DLEN)
        {
            t=0;
            k=i-DLEN+1;
            if(k<0)k=0;
            for(int j=k; j<=i; j++)
                t=t*10+s[j]-'0';
            a[index++]=t;
        }
    }
    BigNum::BigNum(const BigNum &T):len(T.len) //拷贝构造函数
    {
        int i;
        memset(a,0,sizeof(a));
        for(i=0; i<len; i++)
            a[i]=T.a[i];
    }
    BigNum & BigNum::operator=(const BigNum &n) //重载赋值运算符,大数之间赋值运算
    {
        int i;
        len=n.len;
        memset(a,0,sizeof(a));
        for(i=0; i<len; i++)
            a[i]=n.a[i];
        return *this;
    }
    istream& operator>>(istream &in,BigNum &b)
    {
        char ch[MAXSIZE*4];
        int i=-1;
        in>>ch;
        int L=strlen(ch);
        int count=0,sum=0;
        for(i=L-1; i>=0;)
        {
            sum=0;
            int t=1;
            for(int j=0; j<4&&i>=0; j++,i--,t*=10)
            {
                sum+=(ch[i]-'0')*t;
            }
            b.a[count]=sum;
            count++;
        }
        b.len=count++;
        return in;
    }
    ostream& operator<<(ostream& out,BigNum& b) //重载输出运算符
    {
        int i;
        cout<<b.a[b.len-1];
        for(i=b.len-2; i>=0; i--)
        {
            printf("%04d",b.a[i]);
        }
        return out;
    }
    BigNum BigNum::operator+(const BigNum &T)const //两个大数之间的相加运算
    {
        BigNum t(*this);
        int i,big;
        big=T.len>len?T.len:len;
        for(i=0; i<big; i++)
        {
            t.a[i]+=T.a[i];
            if(t.a[i]>MAXN)
            {
                t.a[i+1]++;
                t.a[i]-=MAXN+1;
            }
        }
        if(t.a[big]!=0)
            t.len=big+1;
        else t.len=big;
        return t;
    }
    BigNum BigNum::operator-(const BigNum &T)const //两个大数之间的相减运算
    {
        int i,j,big;
        bool flag;
        BigNum t1,t2;
        if(*this>T)
        {
            t1=*this;
            t2=T;
            flag=0;
        }
        else
        {
            t1=T;
            t2=*this;
            flag=1;
        }
        big=t1.len;
        for(i=0; i<big; i++)
        {
            if(t1.a[i]<t2.a[i])
            {
                j=i+1;
                while(t1.a[j]==0)
                    j++;
                t1.a[j--]--;
                while(j>i)
                    t1.a[j--]+=MAXN;
                t1.a[i]+=MAXN+1-t2.a[i];
            }
            else t1.a[i]-=t2.a[i];
        }
        t1.len=big;
        while(t1.a[len-1]==0 && t1.len>1)
        {
            t1.len--;
            big--;
        }
        if(flag)
            t1.a[big-1]=0-t1.a[big-1];
        return t1;
    }
    BigNum BigNum::operator*(const BigNum &T)const //两个大数之间的相乘
    {
        BigNum ret;
        int i,j,up;
        int temp,temp1;
        for(i=0; i<len; i++)
        {
            up=0;
            for(j=0; j<T.len; j++)
            {
                temp=a[i]*T.a[j]+ret.a[i+j]+up;
                if(temp>MAXN)
                {
                    temp1=temp-temp/(MAXN+1)*(MAXN+1);
                    up=temp/(MAXN+1);
                    ret.a[i+j]=temp1;
                }
                else
                {
                    up=0;
                    ret.a[i+j]=temp;
                }
            }
            if(up!=0)
                ret.a[i+j]=up;
        }
        ret.len=i+j;
        while(ret.a[ret.len-1]==0 && ret.len>1)ret.len--;
        return ret;
    }
    BigNum BigNum::operator/(const int &b)const //大数对一个整数进行相除运算
    {
        BigNum ret;
        int i,down=0;
        for(i=len-1; i>=0; i--)
        {
            ret.a[i]=(a[i]+down*(MAXN+1))/b;
            down=a[i]+down*(MAXN+1)-ret.a[i]*b;
        }
        ret.len=len;
        while(ret.a[ret.len-1]==0 && ret.len>1)
            ret.len--;
        return ret;
    }
    int BigNum::operator%(const int &b)const //大数对一个 int类型的变量进行取模
    {
        int i,d=0;
        for(i=len-1; i>=0; i--)
            d=((d*(MAXN+1))%b+a[i])%b;
        return d;
    }
    BigNum BigNum::operator^(const int &n)const //大数的n次方运算
    {
        BigNum t,ret(1);
        int i;
        if(n<0)exit(-1);
        if(n==0)return 1;
        if(n==1)return *this;
        int m=n;
        while(m>1)
        {
            t=*this;
            for(i=1; (i<<1)<=m; i<<=1)
                t=t*t;
            m-=i;
            ret=ret*t;
            if(m==1)ret=ret*(*this);
        }
        return ret;
    }
    bool BigNum::operator>(const BigNum &T)const //大数和另一个大数的大小比较
    {
        int ln;
        if(len>T.len)return true;
        else if(len==T.len)
        {
            ln=len-1;
            while(a[ln]==T.a[ln]&&ln>=0)
                ln--;
            if(ln>=0 && a[ln]>T.a[ln])
                return true;
            else
                return false;
        }
        else
            return false;
    }
    bool BigNum::operator>(const int &t)const //大数和一个int类型的变量的大小比较
    {
        BigNum b(t);
        return *this>b;
    }
    void BigNum::print() //输出大数
    {
        int i;
        printf("%d",a[len-1]);
        for(i=len-2; i>=0; i--)
            printf("%04d",a[i]);
        printf("
    ");
    }
    
    BigNum num[105];
    BigNum dp[105][105];
    BigNum dow[85];
    int main()
    {
    #ifdef local
    
        int _time=clock();
    #endif
        int n,m;
        cin>>n>>m;
        dow[0]=1;
        for(int i=1; i<=80; i++)
        {
            dow[i]=dow[i-1]*2;
        }
        BigNum ans=0;
        for(int i=0; i<n; i++)
        {
            for(int j=1; j<=m; j++)
            {
                cin>>num[j];
            }
            memset(dp,0,sizeof dp);
            BigNum cur=0;
            for(int j=1; j<=m; j++)
            {
                dp[j][0]=dp[j-1][0]+dow[j]*num[j];
                dp[0][j]=dp[0][j-1]+dow[j]*num[m-j+1];
            }
            for(int j=0; j<=m; j++)
            {
                for(int z=0; z<=m-j; z++)
                {
                    if(j-1>=0)
                    {
                        dp[j][z]=dp[j-1][z]+dow[j+z]*num[j];
                    }
                    if(z-1>=0&&dp[j][z-1]+dow[j+z]*num[m-z+1]>dp[j][z])
                    {
                        dp[j][z]=dp[j][z-1]+dow[j+z]*num[m-z+1];
                    }
                }
                if(dp[j][m-j]>cur)
                    cur=dp[j][m-j];
            }
            //  cout<<cur<<endl;
            ans=cur+ans;
        }
        ans.print();
    #ifdef local
        printf("time: %d
    ",int(clock()-_time));
    #endif
    }
    View Code
  • 相关阅读:
    JavaScript技巧
    函数
    windows实现应用双开
    vue组件中name属性有啥作用
    文本超出长度后多余部分显示省略号
    el-tree控件动态获取数据赋值给treeData渲染问题:render-after-expand属性
    elementUI弹框dialog的打开和关闭
    自然语言处理工具之gensim / 预训练模型 word2vec doc2vec
    Linux 根目录空间不足解决方法
    文本挖掘预处理之分词 / 向量化 / TF-IDF / Hash trick 附代码 Demo
  • 原文地址:https://www.cnblogs.com/scau-zk/p/5634669.html
Copyright © 2020-2023  润新知