矩阵取数游戏解题报告

题目描述

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

1.每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有元素;

2.每次取走的各个元素只能是该元素所在行的行首或行尾;

3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号);

4.游戏结束总得分为m次取数得分之和。

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

输入输出格式
输入格式:

输入文件game.in包括n+1行:

第1行为两个用空格隔开的整数n和m。

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

数据范围:

60%的数据满足:1<=n, m<=30,答案不超过10^16

100%的数据满足:1<=n, m<=80,0<=aij<=1000

输出格式:

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

输入输出样例

输入样例#1:
2 3
1 2 3
3 4 2

输出样例#1:
82

一道明显的DP题,但是却考察了高精度计算,因为M最大可以是80,2的80次方明显爆出银河系了...由于本人特别懒,而且对高精并无自信,所以只写了long long的60分代码.
下面来说说DP的思路
首先很明显的一件事情是你可以一行一行的做DP,最后取极大值相加得到最终结果。问题是这个状态怎么定义最合适,一开始我想的是取某个区间能得到的最大状态是什么,但是这里有个问题,状态怎么转移?你无法知道区间中谁是被最后取走的,而这对于解题十分关键。如果你不知道是谁被最后取,那你只能枚举,而这个过程不是很好处理,反正我失败了。最后研究题解发现状态可以定义为,取 i,j为剩余段的最大收益,显然最终状态应该是 f[i][i]+a[i]^M,这样的好处在于状态转移方便了,很明显你只可以从 f[i-1][j]或者f[i][j+1]转移过来,因为一个剩余线段一定是从另外两种不同的更长剩余线段走来的,过程就是被拿走了一个,加上它的值就是新解.
以下是代码。(待我哪天写个高精版本填坑)


include <iostream>
#include <cmath>
#include <cstring>
#define SIZE 100+10
using namespace std;
int N, M;
string a[105][105];
string f[105][105][105];
/*string jia(string s1, string s2) {
    int a[SIZE], b[SIZE], c[SIZE];
    int size_a = s1.size(), size_b = s2.size();
    memset(a, 0, sizeof(a));
    memset(b, 0, sizeof(b));
    memset(c, 0, sizeof(c));
    
    for (int i = 0; i < size_a; i++) a[size_a - i] = s1[i] - '0';
    for (int i = 0; i < size_b; i++) b[size_b - i] = s2[i] - '0';
    
    int size_c = 1, x = 0;
    
    while (size_c <= size_a || size_c <= size_b) {
        c[size_c] = a[size_c] + b[size_c] + x;
        x = c[size_c] / 10;
        c[size_c] %= 10;
        
        size_c++;
    }
    
    c[size_c] = x;
    while (size_c > 1 && c[size_c] == 0) size_c--;
    
    string res;
    res.resize(size_c);
    for (int i = size_c; i >= 1; i--) res[size_c - i] = c[i] + '0';

    return res;
}*/

string cheng(string s1, string s2) {
    int a[SIZE], b[SIZE], c[SIZE];
    int size_a = s1.size(), size_b = s2.size();
    
    memset(a, 0, sizeof(a));
    memset(b, 0, sizeof(b));
    memset(c, 0, sizeof(c));
        
    for (int i = 0; i < size_a; i++) a[size_a - i] = s1[i] - '0';
    for (int i = 0; i < size_b; i++) b[size_b - i] = s2[i] - '0';
    
    for (int i = 1; i <= size_a; i++) {
        int x = 0;
        
        for (int j = 1; j <= size_b; j++) {
            int now = i + j - 1;
            
            c[now] += a[i] * b[j] + x;
            x = c[now] / 10;
            c[now] %= 10;
        }
        
        c[i + size_b] = x;
    }
    
    int size_c = size_a + size_b;
    while (size_c > 1 && c[size_c] == 0) size_c--;
    
    string res;
    res.resize(size_c);
    for (int i = size_c; i >= 1; i--) res[size_c - i] = c[i] + '0';
    
    return res;
}

string jia(string s1, string s2)
{
    int len=max(s1.length(),s2.length());
    int a[50],b[50];
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    for(int i=0;i<s1.length();i++)
    a[s1.length()-1-i]=s1[i]-'0';
    for(int i=0;i<s2.length();i++)
    b[s2.length()-1-i]=s2[i]-'0';
    string ret;
    int ans[50];
    memset(ans,0,sizeof(ans));
    for(int i=0;i<=50;i++)
    ans[i]=0;
    int x=0;
//    cout<<a[len-1];
    for(int i=0;i<len;i++)
    {
        ans[i]=a[i]+b[i]+x;
    //    cout<<ans[i]<<' '<<x<<'\n';
        x=ans[i]/10;
        ans[i]%=10;
    }
    ans[len]=x;
    if(ans[len])
    {
        len++;
    }    
    ret.resize(len);
    for(int i=0;i<len;i++)
    {
//        cout<<ans[i];
        ret[len-1-i]=ans[i]+'0';
    }
//    cout<<'\n';
    return ret;
}
/*string cheng(string s1, string s2)
{
    int a[50], b[50],c[50];
    for(int i=0;i<=50;i++)
    {
        a[i]=0;
        b[i]=0;
        c[i]=0;
    }
    for(int i=0;i<s1.length();i++)
    a[s1.length()-i-1]=s1[i]-'0';
    for(int i=0;i<s2.length();i++)
    b[s2.length()-i-1]=s2[i]-'0';
    for(int i=0;i<s1.length();i++)
    {
        int x=0;
        for(int j=0;j<s2.length();j++)
        {
            int now=i+j;
            c[now]+=a[i]*b[j]+x;
            x=c[now]/10;
            c[now]%=10;
        }
        c[i+s2.length()]=x;
    }
    int len=0;
    while(c[len]!=0)
    {
        len++;
    }
    string ret;
    ret.resize(len);
    for(int i=0;i<len;i++)
    {
        ret[len-i-1]=c[i]+'0';
    }    
//    cout<<ret.size()<<'\n';
    return ret;
}*/
/*string maxs(string s1,string s2)
{
    int i;
    if(s1.size()>s2.size())
    return s1;
    if(s2.size()>s1.size())
    return s2;
    for(i=0;i<s1.length();i++)
    {
        if(s1[i]>s2[i])
        return s1;
        if(s2[i]>s1[i])
        return s2;
    }
    return s1;
}*/
inline string maxs(string a, string b) {
    if (a.size() > b.size()) return a;
    if (a.size() < b.size()) return b;
    for (int i = 0; i < a.size(); i++) {
        if (a[i] > b[i]) return a;
        if (a[i] < b[i]) return b;
    }
    
    return a;
}

string paw[1005];
int main()
{
    int i, j, k;
    cin>>N>>M;
//    cout<<jia("12345",cheng("123","7"));
    paw[0]="1";
    for(i=1;i<=M;i++)
    {
        paw[i]=cheng("2",paw[i-1]);
    }
    for(i=1;i<=N;i++)
    {
        for(j=1;j<=M;j++)
            cin>>a[i][j];
    }
    for(i=1;i<=N;i++)
    {
        for(j=1;j<=M;j++)
        {
            f[i][j][j]=cheng(a[i][j],paw[M]);
        }
    }
    for(i=1;i<=N;i++)
    {
        for(j=M-1;j>=1;j--)
        {
            for(k=1;k+j-1<=M;k++)
            {
                if(k+j-1==k)
                {
                    f[i][k][k+j-1]=jia(f[i][k][k+j-1],maxs(jia(f[i][k-1][k+j-1],cheng(a[i][k-1],paw[M-j])),jia(f[i][k][k+j],cheng(a[i][k+j],paw[M-j]))));
                }
                else
                {
                    f[i][k][k+j-1]=maxs(jia(f[i][k-1][k+j-1],cheng(a[i][k-1],paw[M-j])),jia(f[i][k][k+j],cheng(a[i][k+j],paw[M-j])));
//                    cout<<f[i][k][k+j-1]<<' '<<k<<' '<<k+j-1<<'\n';
                }    
                //f[i][k][k+j-1]=maxs(f[i][k-1][k+j-1]+a[i][k-1]*power(2,M-j),f[i][k][k+j]+a[i][k+j]*power(2,M-j));
            }
        }
    }
    string ans;
    for(i=1;i<=N;i++)
    {
        string tmp="0";
        for(j=1;j<=M;j++)
        {
            tmp=maxs(tmp,f[i][j][j]);
        }
        ans=jia(ans,tmp);
    }
    cout<<ans<<'\n';
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,635评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,628评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,971评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,986评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,006评论 6 394
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,784评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,475评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,364评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,860评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,008评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,152评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,829评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,490评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,035评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,428评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,127评论 2 356

推荐阅读更多精彩内容