【树形DP】HDU 3586 Information Disturbing
通道:http://acm.hdu.edu.cn/showproblem.php?pid=3586
题意:给定n个敌方据点,1为司令部,其他点各有一条边相连构成一棵树,每条边都有一个权值cost表示破坏这条边的费用,叶子节点为前线。现要切断前线和司令部的联系,每次切断边的费用不能超过上限limit,问切断所有前线与司令部联系所花费的总费用少于m时的最小limit
思路:对于上限进行二分,然后通过树形DP进行判断,dp[i]为切断i的所有子孙叶子所花费的最小费用,状态转移方程: if (i->son.len < limit) dp[i] += min(dp[i->son],i->son.len);
代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int VM=1010; const int INF=1000010; //开始设为0x3f3f3f3f给了WA struct Edge{ int to,nxt; int cap; }edge[VM<<1]; int n,m,cnt,head[VM]; int dp[VM],vis[VM]; void addedge(int cu,int cv,int cw){ edge[cnt].to=cv; edge[cnt].cap=cw; edge[cnt].nxt=head[cu]; head[cu]=cnt++; } void DFS(int u,int pre,int lim){ int flag=0; //标记是不是叶子结点 dp[u]=0; for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if(v!=pre){ flag=1; DFS(v,u,lim); if(edge[i].cap<=lim) dp[u]+=min(dp[v],edge[i].cap); else dp[u]+=dp[v]; } } if(!flag) //叶子结点无穷大 dp[u]=INF; } int main(){ //freopen("input.txt","r",stdin); while(~scanf("%d%d",&n,&m)){ if(n==0 && m==0) break; cnt=0; memset(head,-1,sizeof(head)); int MAX=0; int u,v,w; for(int i=1;i<n;i++){ scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); if(w>MAX) MAX=w; } int l=1,r=MAX,ans=-1; while(l<=r){ int mid=(l+r)>>1; DFS(1,-1,mid); if(dp[1]<=m){ ans=mid; r=mid-1; }else l=mid+1; } printf("%d\n",ans); } return 0; }