NOIP2018Day1T3——赛道修建

NOIP2018Day1T3——赛道修建_第1张图片
本质就是贪心,考试的时候太急了,有一些小错误没找出来,丢了50分。
首先二分答案,判断该长度下最多有几条路。
假设二分的这个答案为k。
dp[]表示以该节点为根的子树中最多有几条路。
more[]表示在保证子树中答案最优的情况下,一端为该节点,一端在子树中节点的最长的链。
很明显,对于一个节点,就有子节点个数条路径长度,如果这个值大于k,则dp[u]++,否则存入b[]中
对b排序,从小到大扫,对每一个没有取过的值,二分出能满足条件的没有取过的最小的值,dp[u]++。
最后more[u]=b[]中没有取过的最大的值
其实是一道水题,还是代码功底不够,没调出来。
C o d e : Code: Code

#include
using namespace std;
const int N=50005;
int n,m,head[N*2],dp[N],b[N],more[N],vis[N],tot;
int read()
{
    int x=0,f=1;char s=getchar();
    while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
    while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}
    return x*f;
}
struct node
{
    int vet,nxt,len;
}edge[N*2];
void add(int u,int v,int w)
{
    edge[++tot].vet=v;
    edge[tot].nxt=head[u];
    head[u]=tot;
    edge[tot].len=w;
}
int cmp(int x,int y)
{
    return x=k)dp[u]++;else
                b[++cnt]=more[v]+edge[i].len;
        }
    }
    for(int i=1;i<=cnt;i++)vis[i]=0;
    sort(b+1,b+cnt+1,cmp);
    for(int i=1;i<=cnt;i++)
        if(!vis[i])
        {
            int L=i+1,R=cnt;
            while(L>1;
                if(b[Mid]+b[i]>=k)R=Mid;else L=Mid+1;
            }
            while(L<=cnt&&vis[L])L++;
            if(L>cnt)continue;
            if(b[L]+b[i]>=k&&!vis[L])
            {
                dp[u]++;vis[L]=1;vis[i]=1;
            }else continue;
        }
    for(int i=cnt;i>=1;i--)
        if(!vis[i])
        {
            more[u]=b[i];
            break;
        }
}
int check(int k)
{
    for(int i=1;i<=n;i++)
    {
        dp[i]=0;more[i]=0;
    }
    dfs(1,0,k);
    if(dp[1]>=m)return 1;else return 0;
}
int main()
{
    n=read(),m=read();
    int sum=0;
    for(int i=1;i>1;
        if(check(mid))l=mid;else r=mid-1;
    }
    printf("%d\n",l);
    return 0;
}

你可能感兴趣的:(#,树形dp,#,贪心,NOIP)