HPU 1022 digust——树搜——dfs

题目链接——http://net.hpuacm.cf/contests

题意:

这个世界是由无数的透明房间组成,每间屋子都有一个或者若干个门,这些门将这些房间相连,保证任意两个房间只有一条路径可以相互到达(保证这个世界的结构是一个树形结构)。Philo与A分别处于两个透明的房间内。Philo想要远离 A ,现在请你帮助他。

对于每个房间都有一个编号,两个相邻房间距离是1,已知Philo在x房间,A在y房间,Philo每次移动都会远离A,A会同时选择远离Philo,期间他们的距离只会不断增大。他们停止的条件都是到达不能再往前走的房间,即只有一扇门的房间。

题面大家已经看的差不多了,相信也理解了题意: 给一棵树, 求经过x和y两点的树上最长路径的长度。

输入

第一行一个整数T,表示测试组数. ( 0< T <= 100) 
接下来的每组数据:
一行三个整数 n,x,y , n 表示这个世界房间的个数, x 和 y 即题意 (x != y ,0< n < 1e5).
接下来的n-1行,每行两个整数 a和 b 表示 a 房间与 b房间 之间可以互相到达( 0 <= a , b < n).

输出

每组数据一行,输出一个整数表示最长路径的长度.

HINT : 来自热心学长的提示 :为了降低难度,我们明确告诉大家这这个题的解法很多,不一定要用树形dp

输入样例 1 

1
4 0 1 
0 2
1 2
2 3

输出样例 1

2

相信经过题目提示,大家可以想到这是一个树的dfs,一共经过两次搜索,第一次搜x,y的距离,第二次分别搜索x,y节点到各自子叶末端的最大距离,然后把这三者相加就是结果

代码;

#include<bits/stdc++.h>
using namespace std;

const int maxn=1e5+10;
int vis[maxn];
int ans1,ans2,ans,sum;
int n,x,y;
int flag=0;
vector< pair<int,int> >oj[maxn];

void ini()
{
    for(int i=0;i<=n;i++) oj[i].clear();
    memset(vis,0,sizeof(vis));
    sum=0;
    ans=0;
    ans1=0;
    ans2=0;
    flag=0;
}

void dfs(int v)
{
    if(v==y)
    {
        flag=1;
        return ;
    }
    else
    {
        pair<int,int> t;
        for(int i=0;i<oj[v].size();i++)
        {
            t=oj[v][i];
            if(vis[t.first]==1) continue;
            vis[t.first]=1;
              //sum=+=t.second;
              sum += t.second;
              dfs(t.first);
              if(flag==1) return ;
              sum -= t.second;
              vis[t.first]=0;
        }
    }
}

void dfs2(int v,int e,int sum)
{
    if(oj[v].size()==1&&oj[v][0].first==e) ans=max(ans,sum);//取最大值
    else
    {
        pair<int,int> t;
        for(int i=0;i<oj[v].size();i++)
        {
            t=oj[v][i];
            if ( vis[ t.first ]==1) continue;
            vis[ t.first ] = 1;
            dfs2 ( t.first , v , sum + t.second );
            vis[ t.first ] = 0;
        }
    }
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&x,&y);
        ini();
        for(int i=1;i<=n-1;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            oj[a].push_back(make_pair(b,1));//用pair来保存该点的末尾结点和长度,尽管在这道题长度为1,但是掌握这个思路不失为一个好处
            oj[b].push_back(make_pair(a,1));//无向图所以...
        }
        vis[x] = 1;//先把起始点标记已走,以免回来又搜到x点,导致时间浪费
        dfs(x);//搜x,y的距离,因为两点只有一条路径,所以搜到的值就是最大值
        dfs2(x,x,0);//搜x到末尾的最远距离
        ans1 = ans;
        ans = 0;
        dfs2(y,y,0);
        ans2 = ans;
        cout<< sum + ans1 + ans2 << endl;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_41670466/article/details/81638217