ACboy needs your help
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4491 Accepted Submission(s): 2403
Problem Description
ACboy has N courses this term, and he plans to spend at most M days on study.Of course,the profit he will gain from different course depending on the days he spend on it.How to arrange the M days for the N courses to maximize the profit?
Input
The input consists of multiple data sets. A data set starts with a line containing two positive integers N and M, N is the number of courses, M is the days ACboy has.
Next follow a matrix A[i][j], (1<=i<=N<=100,1<=j<=M<=100).A[i][j] indicates if ACboy spend j days on ith course he will get profit of value A[i][j].
N = 0 and M = 0 ends the input.
Output
For each data set, your program should output a line which contains the number of the max profit ACboy will gain.
Sample Input
2 2
1 2
1 3
2 2
2 1
2 1
2 3
3 2 1
3 2 1
0 0
Sample Output
Source
HDU 2007-Spring Programming Contest
背包九讲中已经很好的介绍了这种问题:
复杂度(n*m*m)
泛化物品
定义
考虑这样一种物品,它并没有固定的费用和价值,而是它的价值随着你分配给它的费用而变化。这就是泛化物品的概念。
更严格的定义之。在背包容量为
V
的背包问题中,泛化物品是一个定义域为
0..V
中的整数的函数
h
,当分配给它的费用为
v
时,能得到的价值就是
h(v)
。
这个定义有一点点抽象,另一种理解是一个泛化物品就是一个数组
h[0..V]
,给它费用
v
,可得到价值
h[V]
。
一个费用为
c
价值为
w
的物品,如果它是
01
背包中的物品,那么把它看成泛化物品,它就是除了
h(c)=w
其它函数值都为
0
的一个函数。如果它是完全背包中的物品,那么它可以看成这样一个函数,仅当
v
被
c
整除时有
h(v)=v/c*w
,其它函数值均为
0
。如果它是多重背包中重复次数最多为
n
的物品,那么它对应的泛化物品的函数有
h(v)=v/c*w
仅当
v
被
c
整除且
v/c<=n
,其它情况函数值均为
0
。
一个物品组可以看作一个泛化物品
h
。对于一个
0..V
中的
v
,若物品组中不存在费用为
v
的的物品,则
h(v)=0
,否则
h(v)
为所有费用为
v
的物品的最大价值。
P07
中每个主件及其附件集合等价于一个物品组,自然也可看作一个泛化物品。
泛化物品的和
如果面对两个泛化物品
h
和
l
,要用给定的费用从这两个泛化物品中得到最大的价值,怎么求呢?事实上,对于一个给定的费用
v
,只需枚举将这个费用如何分配给两个泛化物品就可以了。同样的,对于
0..V
的每一个整数
v
,可以求得费用
v
分配到
h
和
l
中的最大价值
f(v)
。也即
f(v)=max{h(k) +l(v-k)|0<=k<=v}
。可以看到,
f
也是一个由泛化物品
h
和
l
决定的定义域为
0..V
的函数,也就是说,
f
是一个由泛化物品
h
和
l
决定的泛化物品。
由此可以定义泛化物品的和:
h
、
l
都是泛化物品,若泛化物品
f
满足
f(v)=max{h(k)+l(v-k)|0<=k<=v}
,则称
f
是
h
与
l
的和,即
f=h+l
。这个运算的时间复杂度是
O(V^2)
。
泛化物品的定义表明:在一个背包问题中,若将两个泛化物品代以它们的和,不影响问题的答案。事实上,对于其中的物品都是泛化物品的背包问题,求它的答案的过程也就是求所有这些泛化物品之和的过程。设此和为s,则答案就是s[0..V]中的最大值。
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#define oo 0x13131313
using namespace std;
int n,m;
int A[101][101];
void input()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&A[i][j]);
}
void init()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
}
void ADD(int *ans,int *a,int *b)
{
for(int i=0;i<=m;i++)
{
ans[i]=0;
for(int j=0;j<=i;j++)
{
ans[i]=max(ans[i],a[j]+b[i-j]);
}
}
}
void solve()
{
int ans=0;
if(n>=2)
{
ADD(A[0],A[1],A[2]);
for(int i=3;i<=n;i++)
ADD(A[i-2],A[i-3],A[i]);
for(int i=1;i<=m;i++)
ans=max(ans,A[n-2][i]);
printf("%d\n",ans);
}
else
{
for(int i=1;i<=m;i++)
ans=max(ans,A[1][i]);
printf("%d\n",ans);
}
}
int main()
{
// init();
while(cin>>n>>m&&(n||m))
{
input();
solve();
}
}