Information Disturbing HDU - 3586
考察:树形dp+二分
这道题正解思路有点像二分典型题搬石头.本蒟蒻是没想出来...
思路:
这道题有3个限制条件:
- 裁取的边要使得叶子不能到1.
- 裁取的边和要<=m
- 裁取的边的权值要尽量小.
直接递推根本递推不出来,如果设置叶子节点的f[u] = INF,那么叶子结点到父节点之间的边权值一定会被加入答案,但是这样不符合第3个条件.这道题求去掉边的最大值的最小值.可以考虑二分枚举答案.如果当前边大于枚举的答案.这条边就不去掉,如果小于就判断子节点不连通和父节点不连通哪个更小.
状态转移方程: if(w<=mid) f[u]+= min(f[v],w)
else f[u]+=f[v]
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <vector> 6 using namespace std; 7 const int N = 1010,INF = 0x3f3f3f3f; 8 int h[N],idx,n,m,f[N]; 9 bool has_son[N]; 10 struct Road{ 11 int to,ne,w; 12 }road[N<<1]; 13 vector<int> v; 14 void add(int a,int b,int c) 15 { 16 road[idx].w = c,road[idx].to = b,road[idx].ne = h[a],h[a] = idx++; 17 } 18 void dfs(int u,int fa,int t) 19 { 20 f[u] = INF; int tmp = 0; 21 for(int i=h[u];i!=-1;i=road[i].ne) 22 { 23 int v = road[i].to; 24 if(v==fa) continue; 25 dfs(v,u,t); 26 if(road[i].w>t) tmp += f[v]; 27 else tmp += min(f[v],road[i].w); 28 if(tmp>INF) tmp = INF; 29 } 30 if(tmp) f[u] = tmp; 31 } 32 bool check(int t) 33 { 34 dfs(1,-1,t); 35 if(f[1]>m) return false; 36 else return true; 37 } 38 void inits() 39 { 40 idx = 0; v.clear(); 41 memset(h,-1,sizeof h); memset(has_son,0,sizeof has_son); 42 } 43 int main() 44 { 45 while(scanf("%d%d",&n,&m)!=EOF&&(n+m)) 46 { 47 inits(); 48 for(int i=1;i<n;i++) 49 { 50 int x,y,w; scanf("%d%d%d",&x,&y,&w); 51 add(x,y,w); has_son[x] = 1; 52 v.push_back(w); 53 } 54 sort(v.begin(),v.end()); 55 v.erase(unique(v.begin(),v.end()),v.end()); 56 int low = 0,high = v.size()-1; 57 while(low<high) 58 { 59 int mid = low+high>>1; 60 if(check(v[mid])) high = mid; 61 else low = mid+1; 62 } 63 if(check(v[low])) printf("%d\n",v[low]); 64 else printf("-1\n"); 65 } 66 return 0; 67 }