矩阵取数

Description

帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n·m的矩阵,矩阵中的每个元素aij据为非负整数。游戏规则如下:

  1. 每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有的元素;
  2. 每次取走的各个元素只能是该元素所在行的行首或行尾;
  3. 每次取数都有一个得分值,为每行取数的得分之和;每行取数的得分 = 被取走的元素值*2i,其中i表示第i次取数(从1开始编号);
  4. 游戏结束总得分为m次取数得分之和。

帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。

Analysis

因为每行取数的策略可能不同,所以应该分行进行动规讨论。每行都要进行m次取数,每次取数的权值都是上一次的二倍。因为取数的分数是累计的,所以每次取完数后剩下部分也要求出最优策略,具备最优解子结构。那么

dp[i][j]=2*max(s[i]+dp[i+1][j],s[j]+dp[i][j-1])

到这里还没有结束,因为m<=80,所以最大是2^80,约合30位,所以高精度计算。

很坑的地方:因为状态转移中存在do[i+1][j],所以可能会数组越界,不能开到81。

Code

#include <bits/stdc++.h>

int n,m,s[1001];

struct bign{
    int len,num[101];
    bign operator = (bign eq){
        len=eq.len;
        memset(num,0,sizeof(num));
        for(int i=0;i<len;i++)
            num[i]=eq.num[i];
        return *this;
    }
    bign operator + (bign ad){
        bign ans;
        ans.len=std::max(len,ad.len);
        memset(ans.num,0,sizeof(ans.num));
        int accu=0;
        for(int i=0;i<ans.len;i++){
            int res=num[i]+ad.num[i]+accu;
            ans.num[i]=res%10;
            accu=res/10;
        }
        if(accu)ans.num[ans.len++]=accu;
        return ans;
    }
    bign operator + (int ad){
        bign eq;
        eq.len=0;
        memset(eq.num,0,sizeof(eq.num));
        while(ad){
            eq.num[eq.len++]=ad%10;
            ad/=10;
        }
        return *this+eq;
    }   
    bign operator += (bign ad){
        return *this=*this+ad;
    }
    bign operator += (int ad){
        return *this=*this+ad;
    }
    bool operator > (bign ad){
        if(len>ad.len)return 1;
        if(len<ad.len)return 0;
        for(int i=len-1;i>=0;i--)
            if(num[i]>ad.num[i])return 1;
            else if(num[i]<ad.num[i])return 0;
        return 0;
    } 
    friend std::ostream& operator << (std::ostream& out,bign ans){
        for(int i=ans.len-1;i+1;i--)
            out<<ans.num[i];
        return out;
    }
}ans,dp[81][81];

int main(){
    freopen("game.in","r",stdin);
    freopen("game.ans","w",stdout);
    std::cin>>n>>m;
    while(n--){
        for(int i=1;i<=m;i++)
            std::cin>>s[i];
        for(int l=1;l<=m;l++)
            for(int b=1;b<=m-l+1;b++){
                int e=b+l-1;
                bign la,ra;
                la=dp[b+1][e]+s[b];
                ra=dp[b][e-1]+s[e];
                dp[b][e]=la>ra?la+la:ra+ra;
            }
        ans+=dp[1][m];
    }
    std::cout<<ans<<std::endl;
    return 0;
}

转载于:https://www.cnblogs.com/qswx/p/9492520.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值