Information Disturbing
题目:http://acm.hdu.edu.cn/showproblem.php?pid=3586
题意:给定n个敌方据点,1为司令部,其他点各有一条边相连构成一棵树,每条边都有一个权值cost表示破坏这条边的费用,叶子节点为前线。现要切断前线和司令部的联系,每次切断边的费用不能超过上限limit,问切断所有前线与司令部联系所花费的总费用少于m时的最小limit。
题解:一般看出这题要树形DP不难,但是难在想到要二分。对于上限进行二分,然后通过树形DP进行判断。
代码:
#include<cstdio>
#include<cstring>
using namespace std;
#define MAX 1010
#define inf (0xfffff)
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
int edge[MAX<<1];//表示第i条边的终点
int next[MAX<<1];//与第i条边同起点的下一条边的位置
int head[MAX<<1];//以i为起点的第一条边的储存位置
int cost[MAX<<1];
int dp[MAX];
void insert(int i,int a,int b,int c)//a起点,b终点
{
edge[i]=b;
next[i]=head[a];
head[a]=i;
cost[i]=c;
}
void dfs(int x,int pre,int maxx)
{
bool flag=false;
int total=0;
for(int i=head[x]; i!=-1; i=next[i])
{
int k=edge[i];
if(k!=pre)
{
flag=true;
dfs(k,x,maxx);
if(cost[i]>maxx) total+=dp[k];
else total+=min(dp[k],cost[i]);
}
}
if(flag) dp[x]=total;
else dp[x]=inf;
}
int main()
{
int n,m;
int a,b,c;
for(; scanf("%d%d",&n,&m);)
{
if(n+m==0) break;
int len=0,ans=inf;
memset(head,-1,sizeof(head));
memset(next,-1,sizeof(next));
for(int i=1,j=1; i<n; ++i)
{
scanf("%d%d%d",&a,&b,&c);
insert(j++,a,b,c);
insert(j++,b,a,c);
len=max(c,len);
}
int l=1,r=len,mid;
for(; l<=r;)
{
memset(dp,0,sizeof(dp));
mid=(l+r)>>1;
dfs(1,-1,mid);
if(dp[1]<=m)
{
ans=mid;
r=mid-1;
}
else
l=mid+1;
}
if(ans==inf) puts("-1");
else printf("%d\n",ans);
}
return 0;
}
来源:
http://blog.youkuaiyun.com/ACM_Ted