看到这道题的第一眼就感觉应该是树形动态规划,任何一个结点都只有两个选择,使用信息放大器,或者不使用信息放大器。首先想到的使用一个二维数组,d[i][0]为这个节点使用信息放大器,d[i][1]不使用信息放大器。但是就发现了一个问题,在不使用信息放大器的情况下,到该节点的信息大小是不一样的。所以最后只用了一个一维数组记录,只记录使用信息放大器的情况。
每到一个节点,都先判断其节点到子节点需要信息放大器吗。如果需要信息放大器,就只有使用信息放大器一种情况,如果不需要信息放大器,就有使用信息放大器,和不使用信息放大器两种情况
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXN = 20005;
struct Edge {
int node, decay;
Edge(int a, int b): node(a), decay(b){};
};
vector<Edge> edges[MAXN];
int n, d[MAXN], strength, maxDecay = 0; // 记录d[i]使用信息放大器的情况下,其子节点需要使用多少个信息放大器
bool vis[MAXN], v[MAXN]; // vis是用来记录d[i][j]是否拜访过,v是用来防止重复访问节点
void read () {
scanf("%d", &n);
for (int i = 1, m, a, b; i <= n; i++) {
scanf("%d", &m);
for (int j = 0; j < m; j++) {
scanf("%d %d", &a, &b);
maxDecay = max(maxDecay, b);
Edge u = Edge(a, b);
edges[i].push_back(u);
}
}
scanf("%d", &strength);
}
int dp (int i, int s) {
int maxs = 0;
for (int j = 0; j < edges[i].size(); j++) {
if (!v[edges[i][j].node]) {
maxs = max(maxs, edges[i][j].decay);
}
}
if (!vis[i]) {
// 在该结点使用信号发送器
vis[i] = true;
d[i] = 1;
for (int j = 0; j < edges[i].size(); j++) {
if (!v[edges[i][j].node]) {
v[edges[i][j].node] = true;
d[i] += dp(edges[i][j].node, strength - edges[i][j].decay);
v[edges[i][j].node] = false;
}
}
}
if (maxs < s) {
// 在该结点不使用信号发送器
int ans = 0;
for (int j = 0; j < edges[i].size(); j++) {
if (!v[edges[i][j].node]) {
v[edges[i][j].node] = true;
ans += dp(edges[i][j].node, s - edges[i][j].decay);
v[edges[i][j].node] = false;
}
}
return min(ans, d[i]);
}
return d[i];
}
int main () {
read();
if (maxDecay >= strength) {
printf("No solution."); // 如果最大的衰减量大于强度,就一定无法传遍整个网络
} else {
v[1] = true;
d[1] = dp(1, strength);
printf("%d", d[1]);
}
return 0;
}