HDU 3586 Information Disturbing (枚举+树形DP)

来源:互联网 发布:crossover mac破解 编辑:程序博客网 时间:2024/06/15 11:20

题意:给定一个带权无向树,要切断所有叶子节点和1号节点(总根)的联系,每次切断边的费用不能超过上限limit,问在保证总费用<=m下的最小的limit。

按这题的要求:

要使得limit尽可能的小,但是又要满足<=m;这两个是矛盾的,比如:假设切断两个5或切断一个6都可以试树和“1”节点失去联系。因为要使limit小,切断两根用费为5的 比切断一根 花费为6更佳,但是这样总费用却多了4,可能就使得总费用超m了。

所以想在一次dfs里把limit和总费用都解决,几乎是不可能的……所以这题看似是简单,结果想了很久却不会做……

正解是二分枚举limit,初始l=1,r=最大边权;判断在该limit下能否符合m。能则缩小limit,否则增大limit。复杂度是 O(nlogm)完全是可以接受的。

然而我偷了一下懒直接一个for循环拍过去正好卡这个时间过去了(数据强肯定跪)

【代码】

/* ***********************************************Author        :angon************************************************ */#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <stack>#include <vector>#include <queue>#include <set>#include <map>#include <string>#include <math.h>#include <stdlib.h>#include <time.h>using namespace std;#define showtime fprintf(stderr,"time = %.15f\n",clock() / (double)CLOCKS_PER_SEC)#define lld %I64d#define REP(i,k,n) for(int i=k;i<n;i++)#define REPP(i,k,n) for(int i=k;i<=n;i++)#define scan(d) scanf("%d",&d)#define scanl(d) scanf("%I64d",&d)#define scann(n,m) scanf("%d%d",&n,&m)#define scannl(n,m) scanf("%I64d%I64d",&n,&m)#define mst(a,k)  memset(a,k,sizeof(a))#define LL long long#define N 1005#define mod 1000000007inline int read(){int s=0;char ch=getchar();for(; ch<'0'||ch>'9'; ch=getchar());for(; ch>='0'&&ch<='9'; ch=getchar())s=s*10+ch-'0';return s;}struct Edge{    int v,w,next;}edge[N*2];int head[N],tot;void addedge(int u,int v,int w){    edge[tot] = (Edge) {v,w,head[u]};    head[u] = tot++;}int n,m;int dp[N];  //总花费void dfs(int u,int fa,int M){    int flag=0; dp[u]=0;    for(int i=head[u]; ~i; i=edge[i].next)    {        int v = edge[i].v;        int w = edge[i].w;        if(v==fa) continue;        flag=1;        dfs(v,u,M);        if(w > M) //不能切断这条边,那只能靠儿子            dp[u] += dp[v];        else      //能切,则选择小的那个            dp[u] += min(dp[v],w);      }    if(flag==0) dp[u] = 100001;}int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    while(~scann(n,m) && (m||n))    {        mst(head,-1); tot=0;        int maxc=0;        REP(i,1,n)        {            int u,v,w;            scann(u,v);scan(w);            addedge(u,v,w);            addedge(v,u,w);            maxc=max(w,maxc);        }        int flag=0;        for(int i=1;i<=maxc;i++)        {            dfs(1,-1,i);            if(dp[1]<=m)            {                printf("%d\n",i);                flag=1;                break;            }        }        if(!flag)            printf("-1\n");    }    return 0;}



0 0
原创粉丝点击