[每日一题] 2019.3.26 P1269 信号放大器 [树形动态规划]

P1269 信号放大器

看到这道题的第一眼就感觉应该是树形动态规划,任何一个结点都只有两个选择,使用信息放大器,或者不使用信息放大器。首先想到的使用一个二维数组,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;
}

猜你喜欢

转载自blog.csdn.net/AdamAndTina/article/details/88825168