题目大意:给定n个敌方据点,1为司令部,其他点各有一条边相连构成一棵 树,每条边都有一个权值cost表示破坏这条边的费用,叶子节点为前线。现要切断前线和司令部的联系,每次切断边的费用不能超过上限limit,问切断所 有前线与司令部联系所花费的总费用少于m时的最小limit。1<=n<=1000,1<=m<=100万
题目要问的是最小的最大限制,必然二分答案
然后对于每一个值,树形DP判定是否可行
dp[i]表示要切断以i为根的其它所有子树的最小代价。
其中设定叶子结点的代价为无穷大
那么对于某一个非叶子结点,要切断一棵子树就有两种选择,切断以孩子为根的子树或者切断根与孩子的边。
如果根与孩子的边大于限制,那就取无穷大。
最后判断1号结点的总花费是否小于等于m
注意:无穷大不要取太大,否则会连续相加溢出
Sample Input
5 5
1 3 2
1 4 3
3 5 5
4 2 6
0 0
Sample Output
3
1 /* 2 HDU 3586 3 树形DP+二分答案 4 */ 5 #include<stdio.h> 6 #include<string.h> 7 #include<iostream> 8 #include<algorithm> 9 using namespace std; 10 const int MAXN=1010; 11 const int INF=1000010;//这里一定要设得合适,不能太大,不能太小 12 13 struct Node 14 { 15 int to; 16 int next; 17 int w; 18 }edge[MAXN*2]; 19 int head[MAXN]; 20 int tol; 21 int dp[MAXN]; 22 void add(int a,int b,int w) 23 { 24 edge[tol].to=a; 25 edge[tol].next=head[b]; 26 edge[tol].w=w; 27 head[b]=tol++; 28 edge[tol].to=b; 29 edge[tol].next=head[a]; 30 edge[tol].w=w; 31 head[a]=tol++; 32 } 33 34 void init() 35 { 36 tol=0; 37 memset(head,-1,sizeof(head)); 38 } 39 40 void dfs(int u,int pre,int limit) 41 { 42 int flag=false;//标记是不是叶子结点 43 dp[u]=0; 44 for(int i=head[u];i!=-1;i=edge[i].next) 45 { 46 int v=edge[i].to; 47 if(v==pre)continue; 48 flag=true; 49 dfs(v,u,limit); 50 if(edge[i].w<=limit)dp[u]+=min(dp[v],edge[i].w); 51 else dp[u]+=dp[v]; 52 } 53 if(!flag)dp[u]=INF;//叶子结点无穷大 54 } 55 int main() 56 { 57 int n,m; 58 int a,b,w; 59 int l,r,mid; 60 while(scanf("%d%d",&n,&m)==2) 61 { 62 if(n==0&&m==0)break; 63 init(); 64 r=0; 65 for(int i=1;i<n;i++) 66 { 67 scanf("%d%d%d",&a,&b,&w); 68 add(a,b,w); 69 if(w>r)r=w; 70 } 71 l=1; 72 int ans=-1; 73 while(l<=r) 74 { 75 mid=(l+r)/2; 76 dfs(1,-1,mid); 77 if(dp[1]<=m) 78 { 79 ans=mid; 80 r=mid-1; 81 } 82 else l=mid+1; 83 } 84 printf("%d\n",ans); 85 } 86 return 0; 87 }
时间: 2024-10-24 23:09:23