HDU-3586 Information Disturbing(树形DP+删边)
题目大意:一棵有n个节点的有根树,1为根节点,边带权,表示删掉这条边的代价。现在要删掉一些边,使叶子节点不能到达根节点。但是,每次删除的边的代价不能超过limit,删掉的边的总代价不能超过m,求最小的limit的可能取值。
题目分析:二分枚举limit,定义状态dp(u)表示将u与它管辖的叶子节点失去联系所需要的总代价,则:
dp(u)+=min(dp(son),e[i].w),e[i].w<=limit;
dp(u)+=dp(son) e[i].w>limit;
代码如下:
# include<iostream> # include<cstdio> # include<cstring> # include<vector> # include<queue> # include<list> # include<set> # include<map> # include<string> # include<cmath> # include<cstdlib> # include<algorithm> using namespace std; # define LL long long const int N=1005; const int INF=1000001; struct Edge { int w,to,nxt; }; Edge e[N]; int n,m; int du[N]; int maxn,cnt; int dp[N]; int head[N]; void add(int u,int v,int w) { e[cnt].to=v; e[cnt].w=w; e[cnt].nxt=head[u]; head[u]=cnt++; } void init() { int a,b,c; cnt=maxn=0; memset(du,0,sizeof(du)); memset(head,-1,sizeof(head)); for(int i=1;i<n;++i){ scanf("%d%d%d",&a,&b,&c); ++du[a]; ++du[b]; maxn=max(maxn,c); add(a,b,c); add(b,a,c); } } void dfs(int u,int fa,int limit) { //cout<<u<<endl; if(du[u]==1&&u!=1){ dp[u]=INF; return ; } dp[u]=0; for(int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].to; if(v==fa) continue; dfs(v,u,limit); if(e[i].w>limit) dp[u]+=dp[v]; else dp[u]+=min(dp[v],e[i].w); } } int solve() { if(n==1) return 0; int l=1,r=maxn+1; while(l<r){ int mid=l+(r-l)/2; dfs(1,-1,mid); if(dp[1]>m) l=mid+1; else r=mid; } dfs(1,-1,r); if(dp[1]>m) return -1; return r; } int main() { //新的主题 while(~scanf("%d%d",&n,&m)&&(n+m)) { init(); printf("%d\n",solve()); } return 0; }