NOIP2007提高组 矩阵取数
题目描述
帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数。游戏规则如下:
1.每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有元素;
2.每次取走的各个元素只能是该元素所在行的行首或行尾;
3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号);
4.游戏结束总得分为m次取数得分之和。
帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。
输入输出格式
输入格式:
包括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
输出格式:
仅包含1行,为一个整数,即输入矩阵取数后的最大得分。
输入输出样例
输入样例:
2 3
1 2 3
3 4 2
输出样例:
82
分析:
求每一行的最大值,然后将它们的结果相加。
对于第n行,用动态规划的方法:
状态:f(i, j),表示在第i个元素和第j个元素之间操作是的最大值。
初始值:当i==j时,此时只剩些一个元素,因此应该是第m次去,因此f(i, i)= matrix[n][i]*2^m;
状态转移方程:对f(i,j),假设k=j-i+1能到达这种状态,说明已经到了m-k次取数,另一方面,可以从左取数,也可以从右取数,这两种方法的结果较大者即为f(i, j)的值。因此,f(i, j)=max(f(i+1, j) + matrix[n][i]*2^(m-k), f(i, j-1) + matrix[n][j]*2^(m-k)。
题目描述
帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数。游戏规则如下:
1.每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有元素;
2.每次取走的各个元素只能是该元素所在行的行首或行尾;
3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号);
4.游戏结束总得分为m次取数得分之和。
帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。
输入输出格式
输入格式:
包括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
输出格式:
仅包含1行,为一个整数,即输入矩阵取数后的最大得分。
输入输出样例
输入样例:
2 3
1 2 3
3 4 2
输出样例:
82
分析:
求每一行的最大值,然后将它们的结果相加。
对于第n行,用动态规划的方法:
状态:f(i, j),表示在第i个元素和第j个元素之间操作是的最大值。
初始值:当i==j时,此时只剩些一个元素,因此应该是第m次去,因此f(i, i)= matrix[n][i]*2^m;
状态转移方程:对f(i,j),假设k=j-i+1能到达这种状态,说明已经到了m-k次取数,另一方面,可以从左取数,也可以从右取数,这两种方法的结果较大者即为f(i, j)的值。因此,f(i, j)=max(f(i+1, j) + matrix[n][i]*2^(m-k), f(i, j-1) + matrix[n][j]*2^(m-k)。
由于数值会很大,因此必须用高精度计算(对java或c11则很好处理)。
#include
#include
#include
#include
#include
#include
#include
using namespace std; #define N 82 #define BASE 10000 int n, m; int matrix[N][N]; // 高精度计算 struct bigint{ int num[50]; // 50足够了,太大会超时 int len; bigint(): len(0){ for(int i=0; i<50; i++) num[i] = 0; } bigint operator +(bigint b); bigint operator *(bigint b); bigint operator *(int a); bigint operator = (bigint b){ len = b.len; for(int i=0; i
b.len) return 0; else{ for(int i=len-1; i>=0; i--){ if(num[i]
b.num[i]) return 0; } } return 1; } void set(int n){ if(n==0){ num[0] = 0; len = 1; } while(n){ num[len] = n % BASE; len++; n /= BASE; } } void leftmove(int k){ // 将数的右侧加k个0,在乘法中用到 int i; for(i=len; i>=0; i--) num[i+k] = num[i]; for(i=0; i
=0; i--) if(num[i]==0) len--; else break; if(len==0) len = 1; } void print(); }; bigint ans, f[N]; bigint bigint::operator +(bigint b){ int i, carry = 0, len1 = max(len, b.len); bigint tmp; for(i=0; i
0){ tmp.num[len1] = carry % BASE; carry /= BASE; len1++; } tmp.len = len1; tmp.movezero(); return tmp; } bigint bigint::operator *(int a){ int i, carry = 0, len1; bigint tmp; for(i=0; i
=0; i--){ if(i!=len-1){ if(num[i]<10) // 不足4位的补足0,以达到4位 cout<<"000"; else if(num[i]<100) cout<<"00"; else if(num[i]<1000) cout<<"0"; } cout<
'9') ch = getchar(); while(ch<='9' && ch>='0'){ ans = ans * 10 + ch - '0'; ch = getchar(); } return ans; } bigint re[N][N]; void resolve(int n1){ int i, j, k, num ; bigint tmp1, tmp2; for(i=1; i<=m; i++) for(j=1; j<=m; j++){ re[i][j].len = 0; memset(re[i][j].num, 0, sizeof(re[i][j].num)); } // DP for(i=1; i<=m; i++) // 初始化 re[i][i] = f[m] * matrix[n1][i]; for(k=1; k