矩阵取数游戏_洛谷1005_dp

来源:互联网 发布:淘宝上的小样是真的吗 编辑:程序博客网 时间:2024/05/22 06:31

题目描述


帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的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行,为一个整数,即输入矩阵取数后的最大得分。

Analysis


本来一道很水的dp被硬生生加上高精度,调wa到想死(哭泣
首先可以想到这些行之间是没有关系影响的,那么完全可以边读边做,就变成一段序列两边取数字求最大值
两种思路,从两边往中间取,那么f[i][j]表示从前往后取了i个数字,从后往前取了j个数字,
方程 f[i][j]=max{f[i1][j]+num[i]2i+mj+1,f[i][j+1]+num[j]2i+mj+1}
特别的,我们规定f[0][m]只能往后取,f[1][m+1]只能往前取
2的n次方可以打表,高精度压位会比较快

从中间取大概就是每加上一个数字就把转移前的状态*2,不用考虑乘方,不会写
除了高精度基本没难度的题

Code


#include <stdio.h>#include <string.h>#define rep(i, a, b) for (int i = a; i <= b; i ++)#define drp(i, a, b) for (int i = a; i >= b; i --)#define fill(x, t) memset(x, t, sizeof(x))#define maxn 10#define mod 10000#define N 201using namespace std;struct num{    int s[maxn+1];    inline num operator +(num b){        num c = {0};int v = 0;        for (int i = maxn; i > 0; i --){            c.s[i] = (s[i] + b.s[i] + v) % mod;            v = (s[i] + b.s[i] + v) / mod;        }        return c;    }    inline num operator *(num b){        num c = {0}; int v = 0;        for (int i = maxn; i > 0; i --){            for (int j = maxn; j > 0; j --){                c.s[maxn - ((maxn - i + 1) + (maxn - j + 1) - 1) + 1] += s[i] * b.s[j];            }        }        for (int i = maxn; i > 0; i --){            if (c.s[i] >= mod){                c.s[i - 1] += c.s[i] / mod;                c.s[i] = c.s[i] % mod;            }        }        return c;    }    inline num operator /(int x){        num c = {0}; int v = 0;        for (int i = 1; i <= maxn; i ++){            int t = v * mod + s[i];            c.s[i] = t / x;            v = t % x;        }        return c;    }    inline num operator -(num b){        num c = {0}; int v = 0;        for (int i = maxn; i > 0; i --){            if (s[i] - v >= b.s[i]){                c.s[i] = s[i] - b.s[i] - v, v = 0;            }else{                c.s[i] = s[i] - b.s[i] - v + mod, v = 1;            }        }        return c;    }    inline void read(int x){        int cnt = 0;        do{            s[maxn - cnt++] = x % mod;            x /= mod;        }while (cnt <= maxn);    }    inline void output(){        int i = 0;        num tmp = *this;        while (!tmp.s[i] && i < maxn){            i ++;        }        printf("%d", tmp.s[i]);        for (int j = i + 1; j <= maxn; j ++){            int p = 4, f[5];            fill(f, 0);            do{                f[p --] = tmp.s[j] % 10;            }while (tmp.s[j] /= 10);            for (int k = 1; k <= 4; k++){                printf("%d",f[k]);            }        }        printf("\n");    }}map[N][N], f[N][N], p[N];inline int read(){    int x = 0, v = 1;    char ch = getchar();    while (ch < '0' || ch > '9'){        if (ch == '-'){            v = -1;        }        ch = getchar();    }    while (ch <= '9' && ch >= '0'){        x = x * 10 + ch - '0';        ch = getchar();    }    return x * v;}inline num max(num x, num y){    int i = 0;    while (!x.s[i] && i < maxn){        i ++;    }    int j = 0;    while (!y.s[j] && j < maxn){        j ++;    }    int lenx = maxn - i + 1, leny = maxn - j + 1;    if (lenx < leny){        return y;    }else if (lenx > leny){        return x;    }else{        while (i <= maxn && j <= maxn){            if (x.s[i] > y.s[j]){                return x;            }else if (x.s[i] < y.s[j]){                return y;            }            i ++;            j ++;        }    }    return x;}int main(void){    num two;    two.read(2);    p[0].read(1);    rep(i, 1, 81){        p[i] = p[i - 1] * two;    }    int n = read(), m = read();    rep(i, 1, n){        rep(j, 1, m){            map[i][j].read(read());        }    }    num prt;    fill(prt.s, 0);    rep(k, 1, n){        rep(i, 0, m){            drp(j, m + 1, i + 1){                fill(f[i][j].s, 0);                int term = i + m - j + 1;                if (i != 0){                    f[i][j] = map[k][i] * p[term] + f[i - 1][j];                }                if (j != m + 1){                    f[i][j] = max(f[i][j], map[k][j] * p[term] + f[i][j + 1]);                }            }        }        num ans;        fill(ans.s, 0);        rep(i, 0, m){            ans = max(ans, f[i][i + 1]);        }        // ans.output();        prt = prt + ans;    }    prt.output();    return 0;}
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 上古卷轴5东西太多怎么办 上古卷轴天际杀鸡了怎么办 上古卷轴5偷东西被发现怎么办 上古卷轴杀了鸡怎么办 老滚5东西多了怎么办 上古卷轴5被追杀怎么办 全险车自己碰了怎么办 上古卷轴5狗死了怎么办 头发被胶粘住了怎么办 头发被口香糖粘住了怎么办 上古卷轴5杀了npc怎么办 上古卷轴5血太少了怎么办 因牙齿缺失导致变长怎么办 上古卷轴5闪退怎么办? 小米手机4卡顿怎么办 上古卷轴5任务失败怎么办 上古卷轴5爆显存怎么办 老滚5卡住了怎么办 上古卷轴5被木河镇人追杀怎么办 关门的时候有响怎么办 家里门关门太响怎么办 网上赌搏输了2万怎么办 梦见不顺心的事怎么办 振动声桥洗澡时怎么办 同校生2高潮了怎么办 经期血发黑量少怎么办 电脑键盘右边数字键不能用怎么办 御宅伴侣特别卡怎么办 电脑网络出现三角叹号怎么办 同校生2卡顿怎么办 电脑卡了没反应怎么办 促排卵泡多要怎么办 把朋友搞摔倒意外死亡怎么办 猫见到狗受惊了怎么办 头被桌子撞肿了怎么办 鱼缸里的鱼缺氧怎么办 上火眼皮打拉下来怎么办 小孩头敲了个包怎么办 四个月不吃奶怎么办啊 4个月宝宝不吃奶粉怎么办 3个月婴儿不喝奶怎么办