20180828 DP解题报告
保林哥的话
本套题目检验了四类DP,当然DP肯定不仅有这里的几种类型,由于时间有限,简单和稍偏的DP未列举,未考知识点请同学们一定下来练习掌握。注:BCD三题提供简易题目大意,且题目顺序不代表题目的难易梯度,做题顺序和时间请自行把握!!!
T1 HihoCoder 1798 666
Description
如果一个数字字符串(只包含0-9
,可以有前导0
)中出现且只出现1次666
,我们就称这个字符串是好的。
例如1666
、03660666
是好的,6666
、66
、123
不是好的。
请你计算长度为N
的数字字符串中,有多少个是好的。由于总数可能很大,你只需要输出总数模1000000007
的余数。
Input
一个整数N
。
对于30%
的数据,1 ≤ N ≤ 8
对于100%
的数据,1 ≤ N ≤ 1000
Output
一个整数代表答案。
题解
dp[i][j]
表示长度为i
,开头有j
个6
且串中没有666
的串的数量
这道题也就是将一个问题分成许多子问题,再合并求答案
一道比较简单但很好的数位DP
时间复杂度 \(\Theta(n)\)
代码
1 |
|
T2 Hrbust 2160 Hunter
还没做出来,有时间再补
没法补了
T3 HDU 2196 Computer
题目大意
给出一棵树,求出以每个结点为开始的最长路
题解
非常经典的树形DP
首先用邻接表存图(内存限制有点小而且有多组数据不敢用)vector
默认以1
为根结点,找到以每个结点在以自身为根的子树可以走过最长路径的长度(DFS)
再找每个结点向根走的最长路(DFS)
时间复杂度 \(\Theta(n)\)
代码
1 |
|
T4 POJ 3071 Football
题目大意
有\({2}^{n}\)个足球队,定义p[i,j]
为i
队打败j
队的概率,所有p[i,i]
为0
,且1-p[i,j]=p[j,i]
求夺冠几率最高的球队的编号 ## 题解 概率DP,难度不大
dp[i][j]
为i
队赢j
场比赛的概率,然后就简单了
记得要先枚举比赛
时间复杂度 \(\Theta(n \cdot
{2}^{2n})\) ## 代码 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
int n, m;
double p[256][256];
int winner;
double winner_probability, dp[256][16];
int main(int argc, char **argv) {
while (std::cin >> n) {
if (n == -1) return 0;
m = 1 << n;
memset(dp, 0, sizeof(dp));
for (register int i(1); i <= m; ++i) {
dp[i][0] = 1.0;
for (register int j(1); j <= m; ++j) {
scanf("%lf", &p[i][j]);
}
}
for (register int j(1); j <= n; ++j) {
for (register int i(1); i <= m; ++i) {
for (register int k(1); k <= m; ++k) {
if ((((i - 1) >> (j - 1)) ^ 1) == ((k - 1) >> (j - 1))) {
dp[i][j] += dp[i][j - 1] * dp[k][j - 1] * p[i][k];
}
}
}
}
winner_probability = -1, winner = 0;
for (register int i(1); i <= m; ++i){
if (dp[i][n] > winner_probability) {
winner_probability = dp[i][n];
winner = i;
}
}
printf("%d\n", winner);
}
return 0;
}