您的位置:首页 > 其它

NOIP2007 矩阵取数游戏

2016-03-30 17:22 405 查看
3. 矩阵取数游戏

(game.pas/c/cpp)

【问题描述】

帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的 n*m 的矩阵,矩阵中的每个元素 aij 均

为非负整数。游戏规则如下:

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

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

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

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

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

【输入】

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

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

第 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

第 3 次:得分为 3*2 +4*2 =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

【思路】

区间DP+高精度

可以从题目中看出每一行的选取都是独立的,而每一行的最优解共同构成答案,因此对n行分别求解。

对一行而言,状态转移方程:

D[i][j]=max{d[i+1][j]+sq[tmp]*A[i], d[i][j-1]+A[j]*sq[tmp] };

(tmp=n+i-j , sq[i]定义为2^i)

就数据来看我们需要用到高精度。

【代码】

1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<vector>
5 #define FOR(a,b,c) for(int a=(b);a<(c);a++)
6 using namespace std;
7
8 typedef long long LL;
9 const int maxn= 80+5;
10 const int MAXN = 410;
11
12 struct bign
13 {
14     int len, s[MAXN];
15     bign ()
16     {
17         memset(s, 0, sizeof(s));
18         len = 1;
19     }
20     bign (int num) { *this = num; }
21     bign (const char *num) { *this = num; }
22     bign operator = (const int num)
23     {
24         char s[MAXN];
25         sprintf(s, "%d", num);
26         *this = s;
27         return *this;
28     }
29     bign operator = (const char *num)
30     {
31         for(int i = 0; num[i] == '0'; num++) ;  //è¥?°μ?0
32         len = strlen(num);
33         for(int i = 0; i < len; i++) s[i] = num[len-i-1] - '0';
34         return *this;
35     }
36     bign operator + (const bign &b) const //+
37     {
38         bign c;
39         c.len = 0;
40         for(int i = 0, g = 0; g || i < max(len, b.len); i++)
41         {
42             int x = g;
43             if(i < len) x += s[i];
44             if(i < b.len) x += b.s[i];
45             c.s[c.len++] = x % 10;
46             g = x / 10;
47         }
48         return c;
49     }
50     bign operator += (const bign &b)
51     {
52         *this = *this + b;
53         return *this;
54     }
55     void clean()
56     {
57         while(len > 1 && !s[len-1]) len--;
58     }
59     bign operator * (const bign &b) //*
60     {
61         bign c;
62         c.len = len + b.len;
63         for(int i = 0; i < len; i++)
64         {
65             for(int j = 0; j < b.len; j++)
66             {
67                 c.s[i+j] += s[i] * b.s[j];
68             }
69         }
70         for(int i = 0; i < c.len; i++)
71         {
72             c.s[i+1] += c.s[i]/10;
73             c.s[i] %= 10;
74         }
75         c.clean();
76         return c;
77     }
78     bign operator *= (const bign &b)
79     {
80         *this = *this * b;
81         return *this;
82     }
83     bign operator - (const bign &b)
84     {
85         bign c;
86         c.len = 0;
87         for(int i = 0, g = 0; i < len; i++)
88         {
89             int x = s[i] - g;
90             if(i < b.len) x -= b.s[i];
91             if(x >= 0) g = 0;
92             else
93             {
94                 g = 1;
95                 x += 10;
96             }
97             c.s[c.len++] = x;
98         }
99         c.clean();
100         return c;
101     }
102     bign operator -= (const bign &b)
103     {
104         *this = *this - b;
105         return *this;
106     }
107     bign operator / (const bign &b)
108     {
109         bign c, f = 0;
110         for(int i = len-1; i >= 0; i--)
111         {
112             f = f*10;
113             f.s[0] = s[i];
114             while(f >= b)
115             {
116                 f -= b;
117                 c.s[i]++;
118             }
119         }
120         c.len = len;
121         c.clean();
122         return c;
123     }
124     bign operator /= (const bign &b)
125     {
126         *this  = *this / b;
127         return *this;
128     }
129     bign operator % (const bign &b)
130     {
131         bign r = *this / b;
132         r = *this - r*b;
133         return r;
134     }
135     bign operator %= (const bign &b)
136     {
137         *this = *this % b;
138         return *this;
139     }
140     bool operator < (const bign &b)
141     {
142         if(len != b.len) return len < b.len;
143         for(int i = len-1; i >= 0; i--)
144         {
145             if(s[i] != b.s[i]) return s[i] < b.s[i];
146         }
147         return false;
148     }
149     bool operator > (const bign &b)
150     {
151         if(len != b.len) return len > b.len;
152         for(int i = len-1; i >= 0; i--)
153         {
154             if(s[i] != b.s[i]) return s[i] > b.s[i];
155         }
156         return false;
157     }
158     bool operator == (const bign &b)
159     {
160         return !(*this > b) && !(*this < b);
161     }
162     bool operator != (const bign &b)
163     {
164         return !(*this == b);
165     }
166     bool operator <= (const bign &b)
167     {
168         return *this < b || *this == b;
169     }
170     bool operator >= (const bign &b)
171     {
172         return *this > b || *this == b;
173     }
174     string str() const
175     {
176         string res = "";
177         for(int i = 0; i < len; i++) res = char(s[i]+'0') + res;
178         return res;
179     }
180 };
181
182 istream& operator >> (istream &in, bign &x)
183 {
184     string s;
185     in >> s;
186     x = s.c_str();
187     return in;
188 }
189
190 ostream& operator << (ostream &out, const bign &x)
191 {
192     out << x.str();
193     return out;
194 }
195
196 bign d[maxn][maxn];
197 bign A[maxn][maxn];
198 bign sq[maxn];
199 bign ans=0;
200 int n,m;
201
202 int main() {
203     ios::sync_with_stdio(false);
204     cin>>n>>m;
205     FOR(i,1,n+1) FOR(j,1,m+1) cin>>A[i][j];
206     sq[0]=1; FOR(i,1,m+1){ sq[i]=sq[i-1]*2;}   //高精单精乘
207     FOR(T,1,n+1){
208       FOR(l,0,m) FOR(i,1,m-l+1) {  //m
209             int j=i+l , tmp=m+i-j;
210              if(l==0) { d[i][i]=A[T][i]*sq[tmp];continue; }
211              bign v1=d[i+1][j]+A[T][i]*sq[tmp] ,v2= d[i][j-1]+A[T][j]*sq[tmp] ;
212             if(v1>v2)  d[i][j]=v1;  else d[i][j]=v2;   //高精赋值
213       }
214       ans = ans + d[1][m];  //高精高精加
215     }
216     cout<<ans;
217     return 0;
218 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: