题目描述
输入
输出
样例输入
样例输出
思路:
二维的线性动归,状态转移方程:f[i][j] = max{f[i][j], f[i-1][k] + a[i][j-k]} (0<=k<=j)
(k的范围因为题目说M台设备,一个公司既可以都不拥有也可以都拥有,所以k∈[0,j])
所设变量:
int n, m;//n个分公司,m台设备
int a[N][N];//原始数据,a[i][j]表示第i个分公司分到j台设备的盈利
int f[N][N];//f[i][j] 表示前i个公司分配j个设备的最大盈利
根据样例,我们可以得到如下两个表格
a[m][n]数组(注意是 mXn 大小的矩阵)
1 | 2 | 3 | |
1 | 1 | 2 | 3 |
2 | 2 | 3 | 4 |
f[m][n]数组
1 | 2 | 3 | |
1 | 1 | 2 | 3 |
2 | 2 | 3 | 4 |
我们可以细想一下,前 i 个公司分到 j 台设备的最大盈利 = 前 i-1 个公司分到 k 台设备的最大盈利 + 第 i 个公司分到 j-k 台设备的盈利,
显然是正确的,因为前 i-1 个公司分到 k 台设备的最大盈利并不影响后面的状态,也就是说没有后效性(吸取“奶牛的锻炼”一题的教训)
代码:
#include <iostream>
#include <stdio.h>
#include <map>
#include <vector>
using namespace std;
const int N = 110;
int n, m;
int a[N][N];
int f[N][N];//f[i][j] 前i个公司分配j个设备的最大盈利
void dp()
{
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
{
for(int k = 0; k <= j; k++)
f[i][j] = max(f[i][j], f[i-1][k] + a[i][j-k]);
}
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
scanf("%d", &a[i][j]);
dp();
printf("%d", f[m][n]);
return 0;
}
给个复杂的测试数据:
15 10
36 67 86 8 82 88 1 96 75 82
107 68 136 105 99 104 61 176 127 133
184 120 223 179 198 134 113 247 225 205
283 136 273 217 249 140 117 312 296 205
286 207 315 306 291 224 209 346 370 272
292 279 317 332 372 227 223 375 370 295
361 327 363 373 453 277 286 410 463 316
393 413 369 387 542 302 289 419 473 393
425 443 455 407 561 358 336 477 491 445
469 521 554 478 589 440 364 572 537 512
475 534 570 520 603 530 405 574 602 593
496 542 591 547 654 587 431 587 664 637
577 632 657 645 700 635 527 620 680 680
656 643 670 670 730 715 573 676 721 707
713 719 685 685 757 770 642 744 728 745
----------------------------------------
3913
小结:
一开始觉得好难,用了一维的f[N]数组,怎么想都觉得有后效性就放弃了,思路不对,多注意后效性问题,找准子问题,确切决策