Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 542 | Accepted: 149 |
Description
For example your friend Jack wants to travel on the Mediterranean Sea for 20 days and has the following choices:
- if the holiday deadline is 60 days you can get 1000 EUR provided the boat is rented in between 0 and 41 (60days-20days+1) for 20 days;
- if the holiday deadline is 70 days you can get 800 EUR.
If a client does not contribute to the maximization of your profit you can drop that client. You know all the clients and their choices and you must rent the boat according to the order in which the clients submit their requests.
Write a program that, given the clients, computes the largest profit you can get.
Input
- n - the number of clients (n <= 100)
- on n separate lines the number of days (at most 100) each client wishes to rent the boat;
- the total number of choices for all clients;
- the list of choices in the format client_id, deadline, amount_of_money where the client id is a positive integer in the range 1..n and deadline <= 100.
An empty line separates the input data sets.
Output
Sample Input
3 2 2 4 4 1 2 14 3 4 25 2 4 12 3 3 10
Sample Output
26
题目大意:每个客户要问你借船几天,他们都要在截止日期前归还才能获益。如客户 i i i借船20天,截止日期是60天,那么你在0~41天之间借给他都可以获益。
其实是价值变化的01背包问题,在某天前借给客户则有价值,否则价值为0.
传统的01背包,容量是
c
c
c,
i
i
i个物品每个占
x
x
x容量,价值为
v
v
v。
动规公式为:
d
p
[
j
]
=
m
a
x
(
d
p
[
j
]
,
d
p
[
j
−
c
o
s
t
[
i
]
]
+
v
a
l
u
e
[
i
]
)
dp[j] = max(dp[j],dp[j-cost[i] ]+value[i])
dp[j]=max(dp[j],dp[j−cost[i]]+value[i])
这道题为:
- 最多借100天(容量为100)
- n n n个客户( n n n个物品)
- 每个客户借 d a y day day天(每个占 d a y day day容量)
- 截止日期 b b b前归还则有收益 c c c( d a y day day~ b b b的容量之间才有价值 c c c)
d
a
y
[
i
]
day[i]
day[i]表示客户
i
i
i借的天数,
d
p
[
j
]
dp[j]
dp[j]表示前
j
j
j天最大收益,
n
u
m
[
i
]
[
j
]
num[i][j]
num[i][j]表示在第
j
j
j天收回客户
i
i
i的船的收益。
动规公式为:
d
p
[
j
]
=
m
a
x
(
d
p
[
j
]
,
d
p
[
j
−
d
a
y
[
i
]
]
+
n
u
m
[
i
]
[
j
]
)
dp[j] = max(dp[j],dp[j-day[i]]+num[i][j])
dp[j]=max(dp[j],dp[j−day[i]]+num[i][j])
发现了吗?只有价值部分是不一样的,我们只要给
d
a
y
day
day~
b
b
b的容量之间赋价值
c
c
c,其余容量赋0即可。
注意题目要求每个结果之间输出一个空行
AC代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[110];
int num[110][110], day[110];
int main()
{
int t = 0, n, m, i, j, k, a, b, c, ans;
while (~scanf("%d", &n))
{
for (i = 1; i <= n; i++)
scanf("%d", &day[i]);
scanf("%d", &m);
memset(dp, 0, sizeof(dp));
memset(num, 0, sizeof(num));
while (m--)
{
scanf("%d%d%d", &a, &b, &c); //客户 截止日期 获益
for (j = b; j >= day[a]; j--) //在截止日期时收回,记得这里是逆序更新!
{
num[a][j] = max(num[a][j], c);
//printf("num[%d][%d] : %d\n", a, j, num[a][j]);
}
}
for (i = 1; i <= n; i++)
for (j = 100; j >= day[i]; j--)
{
dp[j] = max(dp[j], dp[j - day[i]] + num[i][j]);
//printf("dp[%d] : %d\n", j, dp[j]);
}
ans = 0;
for (i = 0; i <= 100; i++)
ans = max(ans, dp[i]);
if (t != 0)
printf("\n");
t++;
printf("%d\n", ans);
}
}