hdu 3586 树形dp+二分
题目大意:给定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
INF大小要注意搞好
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #include<map> 8 using namespace std; 9 #define MOD 1000000007 10 const int INF=1000010; 11 const double eps=1e-5; 12 typedef long long ll; 13 #define cl(a) memset(a,0,sizeof(a)) 14 #define ts printf("*****\n"); 15 const int MAXN=1005; 16 int n,m,tt,tot=0,head[MAXN],dp[MAXN]; 17 int maxw; 18 struct edge 19 { 20 int to,next; 21 int w; 22 }edge[MAXN*2]; 23 void addedge(int a,int b,int w) 24 { 25 edge[tot].to=a; 26 edge[tot].next=head[b]; 27 edge[tot].w=w; 28 head[b]=tot++; 29 } 30 void init() 31 { 32 memset(head,-1,sizeof(head)); 33 tot=0; 34 maxw=0; 35 } 36 void dfs(int u,int pre,int limit) 37 { 38 int flag=0; 39 for(int i=head[u];i!=-1;i=edge[i].next) 40 { 41 int v=edge[i].to; 42 if(v==pre) continue; 43 flag=1; 44 dfs(v,u,limit); 45 if(edge[i].w<=limit) dp[u]+=min(dp[v],edge[i].w); //切子树,或者切与子树相连的边 46 else dp[u]+=dp[v]; //只能切断子树 47 } 48 if(!flag) dp[u]=INF; //叶子不能切哦 49 } 50 int main() 51 { 52 int i,j,k; 53 #ifndef ONLINE_JUDGE 54 freopen("1.in","r",stdin); 55 #endif 56 while(scanf("%d%d",&n,&m)!=EOF) 57 { 58 init(); 59 if(n==0&&m==0) break; 60 int u,v,w; 61 for(i=1;i<n;i++) 62 { 63 scanf("%d%d%d",&u,&v,&w); 64 addedge(u,v,w); 65 addedge(v,u,w); 66 if(maxw<w) maxw=w; 67 } 68 int l=1,r=maxw; 69 int ans=-1; 70 while(l<=r) 71 { 72 cl(dp); 73 int mid=(l+r)>>1; 74 dfs(1,-1,mid); 75 if(dp[1]<=m) 76 { 77 ans=mid; 78 r=mid-1; 79 } 80 else l=mid+1; 81 } 82 printf("%d\n",ans); 83 } 84 }