Beans
题目在:http://acm.hdu.edu.cn/diy/contest_showproblem.php?pid=1010&cid=11785
仔细分析题目,豆子都在m*n的矩阵中,假设我要选取m[i][j]处的豆子,那么一定不会选取第i-1行和i+1行的豆子,为啦使得最终获得分数最高,既然选啦m[i][j],那么对于m[i][j]不相邻的同行元素也可以选。其实说来说去就是不可以选取相邻行和相邻位置的元素,于是假设我选取啦第i行,则选取第i行中一批不的相邻元素必定存在一个最大和值s[i],对于每一行的s[i],构成的s[n]数组,与刚才处理单行最大和问题一样,选取不相邻的一批s[i]使得最终和最大。现在要解决这样一个问题:存在数列{sn},要求在数列中选取一批下标互不相邻的数使得这批数的和最大。假设m[i]表示最后一步选取的是s[i]的一批数的最大和,那么显然不可以再选择s[i-1],如果倒数第二步选择的是s[i-2],那么m[i]=s[i]+m[i-2],如果倒数第2步选择的是s[i-3],那么m[i]=m[i-3]+s[i],那么倒数第二步可能选取s[i-4]?假设可以,那么显然为了使得m[i]=s[i]+m[i-4],观察可知中间还可以选取s[i-2],这时候得到的m[i]=s[i]+s[i-2]+m[i-4]比刚才假设的最大值还要大,出现矛盾。说明k<i-3的s[k]不可能是最后一步,于是得到啦递推公式:
m[i]=s[i]+max{m[i-2],m[i-3]};
#include<iostream>
using namespace std;
#define size 2001
int b[size][size];
int MaxBeans(int a[], int n);
int DP(int m, int n);
int Max(int a, int b){
return a > b ? a : b;
}
int main(){
int i, j,m,n;
while (cin >> m >> n){
memset(b, 0, sizeof(b));
for (i = 1; i <= m;i++)
for (j = 1; j <= n; j++)
scanf("%d", &b[i][j]);
cout << DP(m, n) << endl;
}
return 0;
}
int MaxBeans(int a[], int n){
int s[size] = {0};
int i;
s[0] = 0, s[1] = a[1], s[2] =a[2];
for (i = 3; i <= n; i++)
s[i] = Max(s[i - 2], s[i - 3])+a[i];
int max =0;
for (i = 1; i <= n;i++)
if (max<s[i])
max = s[i];
return max;
}
int DP(int m, int n){
int i;
int s[size];
for (i = 1; i <= m; i++){
s[i] = MaxBeans(b[i], n);
}
int max= MaxBeans(s, m);
return max;
}