HDU 4586 Information Disturbing 二分+树形dp

来源:互联网 发布:高速微型数据连接器 编辑:程序博客网 时间:2024/05/26 02:52

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=3586

题意

有一个树形网络通信,1号结点是长官,叶子节点是前线通讯士兵,其他节点为中传递信息的士兵。为了打击这个通信网络,使其中任意一个前线士兵的通讯不能到达长官。利用一台机器可以切断士兵之间的通讯,破坏每对可以直接通讯的士兵都需要花费一个代价。在切断的边中,任意一条边的代价不能超过机器能力上限,且代价总和不能超过机器寿命m,求出最小的机器能力上限,且满足使用寿命的限制条件。

思路

先找出所有叶子节点,二分找出最小机器能力上限。dp找出使图不连通的最小代价。
用dp[u] 表示 使u的子树不连通的最小代价。

#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#include<vector>#include<string>#include<queue>#include<stack>#include<set>#include<map>#define ll long longusing namespace std;const int INF = 1e6+10;const ll maxn = 1e3+10;struct edge{    int v,w,next;}e[maxn*2];int head[maxn];int tot,cnt;int leaf[maxn];bool vis[maxn];int dp[maxn];int ans;void add(int u,int v,int w){    e[tot].v=v;    e[tot].w=w;    e[tot].next=head[u];    head[u]=tot++;}void init(int n){    memset(head,-1,sizeof(head));    memset(dp,0,sizeof(dp));    tot=cnt=ans=0;}void find(int u,int fa){    int f=0;    for(int i=head[u];i!=-1;i=e[i].next)    {        int v=e[i].v,w=e[i].w;        if(v==fa)continue;        find(v,u);        f=1;    }    if(f==0)leaf[cnt++]=u;}void dfs(int u,int fa,int lim){    vis[u]=true;    for(int i=head[u];i!=-1;i=e[i].next)    {        int v=e[i].v,w=e[i].w;        if(v==fa)continue;        if(w<=lim)        {            ans+=w;            continue;        }        dfs(v,u,lim);    }}bool check(int lim){    memset(vis,0,sizeof(vis));    ans=0;    dfs(1,-1,lim);    for(int i=0;i<cnt;i++)    if(vis[leaf[i]])return false;    return true;}void dfs2(int u,int fa,int lim)// dp[u] : 代表以u为根结点的子树 使之不连通的最小代价 且满足约束,如果不存在,如果不能使之不连通,值为INF {    dp[u]=0;    for(int i=head[u];i!=-1;i=e[i].next)    {        int v=e[i].v,w=e[i].w;        if(v==fa)continue;        dfs2(v,u,lim);        if(w<=lim)        dp[u]=dp[u]+min(dp[v],w); // u->v 这条边能断          else        dp[u]=dp[u]+dp[v];      // u->v 这条不能断     }    if(dp[u]==0)dp[u]=INF;}int main(){    int n,m,u,v,w;    while(~scanf("%d%d",&n,&m)&&(n+m))    {        init(n);        int r=-INF;        for(int i=0;i<n-1;i++)        {            scanf("%d%d%d",&u,&v,&w);            add(u,v,w);            add(v,u,w);            r=max(r,w);        }        find(1,-1);        int l=1;        while(l<r)        {            int mid = (l+r)>>1;            if(check(mid))            r=mid;            else            l=mid+1;        }        dfs2(1,-1,l);        if(dp[1]>m)        printf("-1\n");        else        printf("%d\n",l);    }}
阅读全文
0 0
原创粉丝点击