codeforce 337D Book of Evil ----树形DP&bfs&树的直径

比较经典的老题

题目意思:给你一颗节点数为n的树,然后其中m个特殊点,再给你一个值d,问你在树中有多少个点到这m个点的距离都不大于d。

这题的写法有点像树的直径求法,先随便选择一个点(姑且设为点1)来遍历一遍树,存下所有点到点1的距离。然后在m个特殊点中找到距离点1最远的点a1.

然后以a1为初始点遍历一遍树,求每一个点到a1的距离,存在dp[i]中。并且再在m个点中找到到a1距离最大的点a2.最后再以a2为初始点遍历一遍树,求到每一个点到a2的距离dp1[i]。然后for遍历所有点,如果dp[i]和dp1[i]都不大于d,那么合法解+1;

这里可以做一个小证明,如果一个点k还能在m个特殊点中找到距离大于到a1和到a2距离的点s的话,那么点k到a1的距离加上点k到s的距离将大于k到a1加上k到a2,那么在第二次搜索中搜到的距离a1最远的点就不应该是a2而是s,所以不成立。由此反证得知。

具体代码如下:

#include<iostream>
#include<vector>
#include<queue>
#include<string.h>
using namespace std;
bool pd[100050];
int dp[100050],dp1[100050];
int dd[100050];
vector<int> a[100050];
int bfs(int u)
{
    memset(pd,false,sizeof(pd));
    memset(dp,0,sizeof(dp));
    pd[u]=1;
    queue<int> q;
    q.push(u);
    while(q.size()!=0)
    {
        int t=q.front();
        q.pop();
        for(int i=0;i<a[t].size();i++)
        {
            int v=a[t][i];
            if(pd[v]) continue;
            //cout<<"w="<<w<<endl;
            
            pd[v]=1;
            dp[v]=dp[t]+1;
            q.push(v);
        }
    }
    return 1;
}
int bfs1(int u)
{
    memset(pd,false,sizeof(pd));
    memset(dp1,0,sizeof(dp1));
    pd[u]=1;
    queue<int> q;
    q.push(u);
    while(q.size()!=0)
    {
        int t=q.front();
        q.pop();
        for(int i=0;i<a[t].size();i++)
        {
            int v=a[t][i];
            if(pd[v]) continue;
            //cout<<"w="<<w<<endl;
            
            pd[v]=1;
            dp1[v]=dp1[t]+1;
            q.push(v);
        }
    }
    return 1;
}
int main()
{
    int i,j,k,l,x,y,n,m,d;
    scanf("%d%d%d",&n,&m,&d);
   // cout<<n<<" "<<m<<" "<<d<<endl;
    for(i=0;i<m;i++) scanf("%d",&dd[i]);
    for(i=0;i<n-1;i++) 
    {
        scanf("%d%d",&x,&y);
        a[x].push_back(y);
        a[y].push_back(x);
    }
    bfs(1);
    int lon=0,a1=1;
    for(i=0;i<m;i++) 
    if(dp[dd[i]]>lon)
    {
        lon=dp[dd[i]];
        a1=dd[i];
    }
    //cout<<lon<<"。。"<<a1<<endl; 
    bfs(a1);
    lon=0;
    for(i=0;i<m;i++) 
    if(dp[dd[i]]>lon)
    {
        lon=dp[dd[i]];
        a1=dd[i];
    }
    //cout<<lon<<"。。"<<a1<<endl; 
    int ans=0;
    bfs1(a1);
    for(i=1;i<=n;i++)
    {
        if(dp[i]<=d&&dp1[i]<=d) ans++;
    }
    //for(i=1;i<=n;i++) cout<<dp[i]<<" "<<dp1[i]<<endl;
    printf("%d
",ans);
}
原文地址:https://www.cnblogs.com/wsblm/p/10726720.html