题解
B - 滑雪
题意
Michael 想知道在一个区域中最长的滑坡。区域由一个行数为 R R R和列数为 C C C二维数组给出。数组的每个数字代表点的高度。下面是一个例子:
16 16 16 17 17 17 18 18 18 19 19 19 6 6 6
15 15 15 24 24 24 25 25 25 20 20 20 7 7 7
14 14 14 23 23 23 22 22 22 21 21 21 8 8 8
13 13 13 12 12 12 11 11 11 10 10 10 9 9 9
一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度会减小。在上面的例子中,一条可行的滑坡为
24
−
17
−
16
−
1
24-17-16-1
24−17−16−1(从
24
24
24开始,在
1
1
1结束)。当然
25
-
24
-
23
-
…
-
3
-
2
-
1
25-24-23-\ldots-3-2-1
25-24-23-…-3-2-1更长。事实上,这是最长的一条。
1
≤
R
,
C
≤
100
1≤R,C≤100
1≤R,C≤100
思路
对于二维数组中的每一点,将从该点出发的最长滑坡长度记录到
d
p
dp
dp数组中。则:
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
]
[
j
−
1
]
,
d
p
[
i
+
1
]
[
j
]
,
d
p
[
i
]
[
j
+
1
]
)
+
1
dp[i][j] = max(dp[i-1][j],dp[i][j-1],dp[i+1][j],dp[i][j+1])+1
dp[i][j]=max(dp[i−1][j],dp[i][j−1],dp[i+1][j],dp[i][j+1])+1
用记忆化搜索的方式实现dp。初始化
d
p
dp
dp数组为
0
0
0,搜索到某一点,四个方向都无法滑,返回1。
代码
#include <bits/stdc++.h>
using namespace std;
int h, l;
int Tmap[105][105];
int dp[105][105] = { 0 };
int book[105][105] = { 0 };
const int dx[4] = { 0,0,1,-1 };
const int dy[4] = { 1,-1,0,0 };
int Tans = 0,ans = 0;
int dfs(int x, int y)
{
if (dp[x][y] != 0)
return dp[x][y];
for (int i = 0; i < 4; i++)
{
int nx = x + dx[i], ny = y + dy[i];
if (nx < 1 || nx > h || ny < 1 || ny > l)
continue;
if (Tmap[nx][ny] < Tmap[x][y] && book[nx][ny] == 0)
{
book[x][y] = 1;
dp[x][y] = max(dfs(nx, ny) + 1,dp[x][y]);
book[x][y] = 0;
}
}
if (dp[x][y] == 0)
dp[x][y] = 1;
return dp[x][y];
}
int main()
{
cin >> h >> l;
for (int i = 1; i <= h; i++)
for (int j = 1; j <= l; j++)
cin >> Tmap[i][j];
for (int i = 1; i <= h; i++)
for (int j = 1; j <= l; j++)
Tans = max(Tans, dfs(i, j));
cout << Tans;
return 0;
}
I - Cow Exhibition G
题意
奶牛想证明它们是聪明而风趣的。为此,贝西筹备了一个奶牛博览会,她已经对
N
N
N头奶牛进行了面试,确定了每头奶牛的智商
S
i
S_i
Si和情商
F
i
F_i
Fi。
贝西有权选择让哪些奶牛参加展览(可以不让任何奶牛参加展览,如果这样做是最好的,输出
0
0
0。)。由于负的智商或情商会造成负面效果,所以贝西不希望出展奶牛的智商之和小于零,或情商之和小于零。满足这两个条件下,她希望出展奶牛的智商与情商之和越大越好,请帮助贝西求出这个最大值。
1
≤
N
≤
400
,
−
1000
≤
S
i
,
F
i
≤
1000
1≤N≤400,-1000≤S_i,F_i≤1000
1≤N≤400,−1000≤Si,Fi≤1000
思路
对于任意一头奶牛都有选和不选两种情况,联想到
01
01
01背包中物品的放与不放。将奶牛的智商之和的背包容量,每头奶牛的智商当作物品体积,情商当作物品价值。
则
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示前
i
i
i头奶牛,智商之和为
j
j
j的情况下情商之和的最大值。滚动数组优化后得到:
d
p
[
j
]
=
m
a
x
(
d
p
[
j
]
,
d
p
[
j
−
S
[
i
]
]
+
F
[
i
]
)
dp[j] = max(dp[j], dp[j - S[i]] + F[i])
dp[j]=max(dp[j],dp[j−S[i]]+F[i])
但是题目中的
S
i
,
F
i
S_i,F_i
Si,Fi可能为负数,将dp数组扩大一倍开到
800005
800005
800005,将
d
p
[
400000
]
dp[400000]
dp[400000]当作智商之和为0的情况。
正常
01
01
01背包滚动数组倒着循环即可,但是此题中
S
i
S_i
Si 有正有负,无法判断是正着循环还是倒着循环,于是可以先判断正负再选择正着循环还是倒着循环。
代码
#include <bits/stdc++.h>
using namespace std;
int dp[800005] = { 0 };//使排列组合后能出现的iq值之和的dp[iq]为eq
int main()
{
memset(dp, ~0x3f3f3f3f, sizeof(dp));//初始化dp数组为计算后也不会溢出的足够大的负数,使排列组合后不能出现的iq值对应eq为负数
dp[400000] = 0;
int n;
int iq[405],eq[405];
cin >> n;
int ans = 0;
for (int i = 0; i < n; i++)
cin >> iq[i] >> eq[i];
for (int i = 0; i < n; i++)
{
if (iq[i] >= 0)
for (int j = 800000; j >= iq[i]; j--)
dp[j] = max(dp[j], dp[j - iq[i]] + eq[i]);
else
for (int j = 0; j <= 800000 + iq[i]; j++)
dp[j] = max(dp[j], dp[j - iq[i]] + eq[i]);
}
for (int i = 400000; i <= 800000; i++)
{
if (dp[i] >= 0)
ans = max(ans, i + dp[i] - 400000);
}
cout << ans;
return 0;
}
M-本题主要考察了找规律
题意
小波奇由于冲动消费,不小心买多了章鱼仙贝,买了一共
m
m
m份章鱼仙贝,于是她只能把这些仙贝分给
n
n
n位朋友。
若小波奇当前还剩下
x
(
x
>
0
)
x(x>0)
x(x>0)个仙贝,并给了一位朋友
y
y
y个仙贝(
x
,
y
x,y
x,y都为整数),则这位朋友对小波奇的好感度将增加
y
/
x
y/x
y/x(这个值可以为小数)。
现在,小波奇可以任意安排送仙贝的顺序和每次送仙贝的个数,但不能给同一个人送两次仙贝,允许最后手中还有剩余的仙贝,允许最终有朋友没有分到仙贝。社恐的朋友非常重要,所以请你帮助小波奇算一算,在最优送仙贝策略下,小波奇和所有人的好感度之和最大为多少(假设初始小波奇和所有人好感度都为
0
0
0)。
(
1
≤
n
,
m
≤
500
)
(1≤n,m≤500)
(1≤n,m≤500)
思路
牛客训练时碰到的感兴趣的
d
p
dp
dp题。被题目坑了,完全没规律
感觉难点主要是看不出来用
d
p
dp
dp来做,建立一个
d
p
dp
dp数组,
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示已经给
i
i
i个人发了仙贝,一共发了
j
j
j个仙贝时获得好感度之和的最大值。则:
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
]
[
j
]
,
d
p
[
i
−
1
]
[
j
−
k
]
+
k
/
(
m
−
j
+
k
)
)
,
0
≤
k
≤
j
dp[i][j] = max(dp[i][j],dp[i - 1][j - k] + k/(m - j + k)),0≤k≤j
dp[i][j]=max(dp[i][j],dp[i−1][j−k]+k/(m−j+k)),0≤k≤j
代码
#include <bits/stdc++.h>
using namespace std;
double dp[505][505] = { 0 };
int main()
{
int n, m;
cin >> n >> m;
for(int i = 1;i <=n;i++)
for(int j = 1;j <=m;j++)
for(int k = 0;k <= j;k++)
dp[i][j] = max(dp[i][j],dp[i - 1][j - k] + (double)k/(m - j + k));
printf("%.9lf",dp[n][m]);
return 0;
}