二分+树形dp
题意: 给出一棵树,树的叶子节点是前线,节点1是总指挥的地方。 现在想破环一些边让前线上的点都不能给1发送消息。现在想要使破坏边的最大值最小,同时还要让总的费用不超过m。单的个数为不超过1000, m不超过1000000.
每条边的值不超过1000.
思路: 这道题是很明显的树形dp。 由于要让最大的值最小,所以可以想到二分。 二分这个最大值。然后进行树形dp,看总的消耗费用是否大于m。 关于dp的方程很简单,这里就不写了。
AC代码:
View Code
#include <iostream> #include <cstdio> #include <cstring> #include <string> using namespace std; const int N = 1005, INF = 1<<25; struct EDGE { int u, v, w, next; }edge[N*2]; int dp[N], n, m, num, head[N]; void add(int u, int v, int w) { edge[num].u = u; edge[num].v = v; edge[num].w = w; edge[num].next = head[u]; head[u] = num++; } void init() { num = 0; memset(head, -1, sizeof(head)); int u, v, w; for(int i=1; i<n; i++) { scanf("%d%d%d", &u, &v, &w); add(u, v, w); add(v, u, w); } } void dfs(int u, int pre, int ww) { int v, tp = 0, w; bool flag = 0; for(int i=head[u]; i!=-1; i=edge[i].next) { v = edge[i].v; w = edge[i].w; if(v == pre) continue; flag = 1; dfs(v, u, ww); if(w > ww) tp += dp[v]; else tp += min(w, dp[v]); if(tp >= INF) tp = INF; } if(flag) { dp[u] = tp; } } void solve() { int ans = INF, left=0, right = 1005, mid; while(left <= right) { mid = (left+right)>>1; for(int i=1; i<=n; i++) { dp[i] = INF; } dfs(1, -1, mid); if(dp[1] <= m) { ans = min(ans, mid); right = mid - 1; } else left = mid+1; } if(ans == INF) printf("-1\n"); else printf("%d\n", ans); } int main() { while(scanf("%d%d", &n, &m) != EOF) { if(n == 0 && m == 0) break; init(); solve(); } return 0; }


浙公网安备 33010602011771号