HDU 3586 Information Disturbing
二分+树形DP验证。
答案是通过二分查找得到的,对于每一次二分到的值,进行验证,是否可行。
可以用树形DP来求解所有叶子节点不能向根节点传送消息的最小费用,dp[i] 表示 节点i 的子树的叶子结点都不能向i传送消息的最小费用,这样很容易递推。
#include<cstdio> #include<cstring> #include<cmath> #include<ctime> #include<map> #include<vector> #include<string> #include<algorithm> #include<iostream> using namespace std; int n,m; const int maxn=1000+10; struct Edge { int to; int val; Edge (int u,int v){to=u;val=v;} }; vector<Edge>tree[maxn]; bool vis[maxn]; int dp[maxn]; void init() { for(int i=0;i<=n;i++) tree[i].clear(); memset(vis,0,sizeof vis); memset(dp,-1,sizeof dp); } void read() { for(int i=1;i<=n-1;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); Edge e1(v,w); Edge e2(u,w); tree[u].push_back(e1); tree[v].push_back(e2); } } void dfs(int now,int lim) { bool fail=1; for(int i=0;i<tree[now].size();i++) if(!vis[tree[now][i].to]) fail=0; if(fail) return; bool x=0; int sum=0; for(int i=0;i<tree[now].size();i++) { if(!vis[tree[now][i].to]) { vis[tree[now][i].to]=1; dfs(tree[now][i].to,lim); if(dp[tree[now][i].to]!=-1) sum=sum+min(tree[now][i].val,dp[tree[now][i].to]); else { if(tree[now][i].val<=lim) sum=sum+tree[now][i].val; else x=1; } } } if(!x) dp[now]=sum; } bool work(int lim) { memset(dp,-1,sizeof dp); memset(vis,0,sizeof vis); vis[1]=1; dfs(1,lim); if(dp[1]==-1||dp[1]>m) return 0; return 1; } void BinarySearch() { int left=1,right=1000,mid; int ans; if(!work(2000)) ans=-1; else { while(left<=right) { mid=(left+right)/2; if(work(mid)) ans=mid,right=mid-1; else left=mid+1; } } printf("%d\n",ans); } int main() { while(~scanf("%d%d",&n,&m)) { if(!n&&!m) break; init(); read(); BinarySearch(); } return 0; }