HDU
来源:互联网 发布:js substr 编辑:程序博客网 时间:2024/05/22 08:19
传送门
//题意: 1是总部, 要切断所有叶结点和总部的联系, 每天变有个花费, 要保证总花费在小于m的情况下的最小的limit(每条边的花费要小于limit).
//思路: 这个前提看似非常矛盾, 因为加入砍去两条边权为5的比砍去一条边长为6的limit的要更小一点, 但是有可能总和又要超过m,所以要综合考虑到两部分. 那么采用二分答案, 然后check当前这个答案, 如果合适就减小当前的答案. 然后check用树形dp做, dp[i] 代表 砍掉i小面所有的叶子结点的联系在mid的限制下的最小花费和. 然后细节请看代码
AC Code
const int maxn = 1e3+5;int cnt,head[maxn],dp[maxn];int n,m;struct node{ int to,w,next;}e[maxn*maxn];void add(int u,int v,int w){ e[cnt] = (node){v,w,head[u]}; head[u] = cnt++;}void dfs(int u,int fa,int mid){ int flag = 0; for(int i=head[u]; ~i ; i =e[i].next){ int to = e[i].to; if(fa == to) continue; flag = 1; dfs(to,u,mid); if(e[i].w > mid) dp[u] += dp[to]; //如果这条边不满足.那么只有从它的儿子里面选. else dp[u] += min(dp[to], e[i].w); //否则在儿子中与当前这条边取一个较小的值. } if(!flag) dp[u] = maxn*maxn; //这个取大一点,反正要比m大.}void solve(){ while(~scanf("%d%d",&n,&m) && n && m){ if(n == 1){ printf("0\n"); continue; } cnt = 0; Fill(head,-1); int mx = 0; for(int i=1;i<n;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); add(v,u,w); mx = max(mx,w); } int l = 0, r = mx,res = inf; while(r - l >= 0){ int mid = (r+l)>>1; Fill(dp,0); dfs(1,-1,mid); if(dp[1] <= m ){ r = mid - 1; res = mid; } else l = mid + 1; } if(res == inf) printf("-1\n"); else printf("%d\n",res); }}
阅读全文
0 0