1. 程式人生 > >dp算法第二發之noip矩陣取數遊戲

dp算法第二發之noip矩陣取數遊戲

space lpad with cell false 空格 memset 文件 urn

dp+高精度。希望通過此題了解高精度。

矩陣取數遊戲

(game.pas/c/cpp)

【問題描述】

帥帥經常跟同學玩一個矩陣取數遊戲:對於一個給定的n*m的矩陣,矩陣中的每個元素aij均為非負整數。遊戲規則如下:

  1. 每次取數時須從每行各取走一個元素,共n個。m次後取完矩陣所有元素;
  2. 每次取走的各個元素只能是該元素所在行的行首或行尾;
  3. 每次取數都有一個得分值,為每行取數的得分之和,每行取數的得分 = 被取走的元素值*2i,其中i表示第i次取數(從1開始編號);
  4. 遊戲結束總得分為m次取數得分之和。

帥帥想請你幫忙寫一個程序,對於任意矩陣,可以求出取數後的最大得分。

【輸入】

輸入文件game.in包括n

+1行:

第1行為兩個用空格隔開的整數nm

第2~n+1行為n*m矩陣,其中每行有m個用單個空格隔開的非負整數。

【輸出】

輸出文件game.out僅包含1行,為一個整數,即輸入矩陣取數後的最大得分。

【輸入輸出樣例1】

game.in

game.out

2 3

1 2 3

3 4 2

82

【輸入輸出樣例1解釋】

第1次:第1行取行首元素,第2行取行尾元素,本次得分為1*21+2*21=6

第2次:兩行均取行首元素,本次得分為2*22+3*22=20

第3次:得分為3*23+4*23=56。總得分為6+20+56=82

【輸入輸出樣例2】

game.in

game.out

1 4

4 5 0 5

122

【輸入輸出樣例3】

game.in

game.out

2 10

96 56 54 46 86 12 23 88 80 43

16 95 18 29 30 53 88 83 64 67

316994

【限制】

60%的數據滿足:1<=n, m<=30, 答案不超過1016

100%的數據滿足:1<=n, m<=80, 0<=aij<=1000

代碼:

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

const int N = 82, M = 32;

struct Bigint{

int data[M];

Bigint(){

memset(data,0,sizeof(data));

data[0] = 1;

}

Bigint(int x){

memset(data,0,sizeof(data));

data[0] = 1;

if (x==0) return;

int i=0;

while (x){

data[++i] = x%10;

x /= 10;

}

data[0] = i;

}

Bigint operator +(const Bigint &x){

Bigint c;

c.data[0] = max(data[0],x.data[0]);

for (int i=1;i<=c.data[0];i++){

c.data[i] += data[i]+x.data[i];

c.data[i+1] += c.data[i]/10;

c.data[i] %= 10;

}

if (c.data[c.data[0]+1]) c.data[0]++;

return c;

}

Bigint operator *(const int &x){

Bigint c;

c.data[0] = data[0];

int i;

for (i=1;i<=data[0];i++)

c.data[i] = data[i]*x;

for (i=1;i<=c.data[0] || c.data[i];i++)

c.data[i+1] += c.data[i]/10,

c.data[i] %=10;

c.data[0] = --i;

return c;

} //不考慮x為0情況

Bigint operator *(const Bigint &x) {

Bigint c;

c.data[0] = data[0]+x.data[0]-1;

for (int i=1;i<=data[0];i++)

for (int j=1;j<=x.data[0];j++)

c.data[i+j-1] += data[i]*x.data[j];

for (int i=1;i<=c.data[0];i++)

c.data[i+1] += c.data[i]/10,

c.data[i] %= 10;

if (c.data[c.data[0]+1]) c.data[0]++;

return c;

}

bool operator < (const Bigint &x)const{

if (data[0]!=x.data[0]) return data[0]<x.data[0];

for (int i=data[0];i>0;i--)

if (data[i]!=x.data[i])

return data[i]<x.data[i];

return false;

}

};

ostream& operator << (ostream& out, const Bigint &x){

for (int i=x.data[0];i>0;i--)

out<<x.data[i];

return out;

}

int a[N][N];

Bigint f[N][N][N]={0},pow2[N],ans(0);

int main(){

freopen("game.in","r",stdin);

freopen("game.out","w",stdout);

ios::sync_with_stdio(false);

int n,m;

cin>>n>>m;

for (int i=1;i<=n;i++)

for (int j=1;j<=m;j++)

cin>>a[i][j];

pow2[0] = 1;

for (int i=1;i<=m;i++) pow2[i] = pow2[i-1]*2;

Bigint t,c,d;

for (int k=1;k<=n;k++){

for (int i=1;i<=m;i++)

for (int j=0;j<=i;j++)

if (j==0) f[k][i][j] = f[k][i-1][0]+pow2[i]*a[k][m-i+1]; //全右邊取

else if (j==i) f[k][i][j] = f[k][i-1][i-1]+pow2[i]*a[k][i];//全左邊取

else {

c = f[k][i-1][j-1]+pow2[i]*a[k][j];

d = f[k][i-1][j]+pow2[i]*a[k][m-(i-j)+1];

f[k][i][j]= c<d?d:c;

}

t = 0;

for (int j=0;j<=m;j++)

if (t<f[k][m][j])

t = f[k][m][j];

ans = ans+t;

}

cout<<ans<<endl;

return 0;

}

dp算法第二發之noip矩陣取數遊戲