HDU_3660
首先如果下一步到达某个节点后,无论怎么走都不能使路径和在L、R之内的话,那么是肯定不能走这一步的。至于如何找到这些不能走的节点,可以从叶子节点开始,如果这条路径和不在L、R之内,那么就将这个叶子标记为-1,表示不能来这个节点,对于其他的节点,如果它的所有孩子都被标记成了-1,那么它本身也应被标记-1。
这样我们只要沿不是-1的点走就可以了,接下来如何计算最大的可能值呢?对于Bob来讲,显然应该在所有的路中挑“最终可能得到的值最大”的那条路去走,而Alice就应该选择“最终可能得到的值最小”的那条路去走,那怎么才能知道最终可能的值是多少呢?只要从叶子节点开始向上依次计算就可以了。
此外,这个题目不用读入优化的话比较容易超时。
#include<stdio.h> #include<string.h> #include<algorithm> #define MAXD 500010 #define INF 0x3f3f3f3f int N, L, R, first[MAXD], e, next[MAXD], v[MAXD], w[MAXD], col[MAXD], dp[MAXD], dis[MAXD]; int q[MAXD]; void add(int x, int y, int z) { v[e] = y, w[e] = z; next[e] = first[x], first[x] = e ++; } void scan(int &a) { char c; while ((c = getchar()) == ' ' || c == '\n'); a = c - 48; while ((c = getchar()) >= '0' && c <= '9') a = (a << 3) + (a << 1) + c - 48; } void init() { int i, x, y, z; memset(first, -1, sizeof(first[0]) * N), e = 0; for(i = 1; i < N; i ++) scan(x), scan(y), scan(z), add(x, y, z); } void solve() { int i, j, x, rear = 0, flag; col[0] = 1, dis[0] = 0, q[rear ++] = 0; for(i = 0; i < rear; i ++) { x = q[i]; for(j = first[x]; j != -1; j = next[j]) col[v[j]] = col[x] ^ 1, dis[v[j]] = dis[x] + w[j], q[rear ++] = v[j]; } for(i = rear - 1; i >= 0; i --) { x = q[i]; flag = 0; if(col[x] == 0) { dp[x] = INF; for(j = first[x]; j != -1; j = next[j]) { flag = 1; if(dp[v[j]] != -1) dp[x] = std::min(dp[x], dp[v[j]] + w[j]); } } else { dp[x] = -INF; for(j = first[x]; j != -1; j = next[j]) { flag = 1; if(dp[v[j]] != -1) dp[x] = std::max(dp[x], dp[v[j]] + w[j]); } } if(flag == 0) dp[x] = dis[x] >= L && dis[x] <= R ? 0 : -1; else if(dp[x] == INF || dp[x] == -INF) dp[x] = -1; } if(dp[0] >= L && dp[0] <= R) printf("%d\n", dp[0]); else printf("Oh, my god!\n"); } int main() { while(scanf("%d%d%d", &N, &L, &R) == 3) { init(); solve(); } return 0; }