您的位置:首页 > 其它

NOIP2007提高组——矩阵取数游戏(game)

2017-05-09 16:12 260 查看




题目描述

帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的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个用单个空格隔开的非负整数。

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

数据范围:

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

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

【题解】
很明显,行之间是完全没有关系的。所以,对于每一行,可以用Dp来求解。。。
设f[i][j] 为区间i,j内的最大值。则:f[i][j] = max(f[i+1][j] * 2 + f[i][i] , f[i][j-1] * 2 + f[j][j])。
边界条件为f[i][i] = a[i] * 2。也就是说,当只有一个数x的时候,它的得分为x * 2^1 = 2x

但这样做的话,很明显会爆int(大于2^80),所以,还要加一个高精度就可以了。
如果觉得麻烦,可以定义大整数类,和重载运算符之类的。

【程序】

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
using namespace std;
#define Maxn 82
#define Maxm 110

struct Bignum{
int len;
int a[Maxm];
Bignum()
{
len = 0;
memset(a,0,sizeof(a));
}
};

Bignum ans;
Bignum f[Maxn][Maxn];

int n,m;

Bignum operator +(const Bignum &A,const Bignum &B)
{
Bignum C;
C.len = max(A.len , B.len);
for(int i=1;i<=C.len;i++)
{
C.a[i] += A.a[i] + B.a[i];
if(C.a[i] >= 10)
{
C.a[i+1] = 1;
C.a[i] -= 10;
}
}
if(C.a[C.len+1] > 0) C.len++;
return C;
}

Bignum Max(const Bignum &A,const Bignum &B)
{
if(A.len > B.len) return A;
if(B.len > A.len) return B;
for(int i=A.len;i>=1;i--)
if(A.a[i] > B.a[i]) return A;
else if(B.a[i] > A.a[i]) return B;
return A;
}

void GetBignum(Bignum &B,int b)
{
B.len = 0;
memset(B.a,0,sizeof(B.a));
if(!b)
{
B.len = 1;
B.a[1] = 0;
return ;
}
while(b)
{
B.len++;
B.a[B.len] = b%10;
b/=10;
}
}

void print(const Bignum &A) { for(int i=A.len;i>=1;i--) printf("%d",A.a[i]); }

int main()
{
scanf("%d%d",&n,&m);

int x;

for(int j=1;j<=n;j++)
{
memset(f,0,sizeof(f));

for(int i=1;i<=m;i++)
{
scanf("%d",&x);
GetBignum(f[i][i],x<<1);
}

for(int le=1;le<m;le++)
for(int l=1;l<=m-le;l++)
{
int r = l + le;
f[l][r] = Max(f[l+1][r] + f[l+1][r] + f[l][l] , f[l][r-1] + f[l][r-1] + f[r][r]);
}

ans = ans + f[1][m];
}

print(ans);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  DP 解题报告