链接:http://acm.hdu.edu.cn/showproblem.php?pid=4607

题意:前一阵子做的,题意忘记了,大体就是求树的直径,就是树的最长路的长度。

思路:树的直径有这么一个算法,从树上任意一点出发,找一条最长路,终点为A,再从A点出来,找一条最长路,终点为B,那么树的直径就是AB的长度。求最长路可用dfs或者spfa来写。

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;

const int maxn=100000+5;
const int INF=0x3f3f3f3f;//不能随便写,不然后面的memset出错
int n,m;
vector<int> list[maxn];
queue<int> q;
int dis[maxn];
int inq[maxn];

void spfa(int p)
{
    int u;
    memset(dis,0x3f,sizeof(dis));
    memset(inq,0,sizeof(inq));
//for(int i=0;i<=n;i++)
//{
//    dis[i]=INF;
//    inq[i]=0;
//}
    dis[p]=0;inq[p]++;
    q.push(p);
    while(!q.empty())
    {
        u=q.front();
        q.pop();inq[u]--;//因为某个点可能重复入队,所以出队的时候也要标记,和bfs不同,bfs只用入队标记,因为只入队一次
        for(int i=0;i<list[u].size();i++)
            if(dis[u]+1<dis[list[u][i]])
            {
                dis[list[u][i]]=dis[u]+1;
                if(inq[list[u][i]]==0)
                {
                    q.push(list[u][i]);
                    inq[list[u][i]]++;
                }
            }
    }
}
int main()
{
    int t,u,v,k;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            list[i].clear();
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            list[u].push_back(v);
            list[v].push_back(u);
        }
        int p=1;
        spfa(p);
        for(int i=2;i<=n;i++)
            if(dis[i]>dis[p])
               p=i;
        spfa(p);
        for(int i=2;i<=n;i++)
            if(dis[i]>dis[p])
               p=i;
        p=dis[p];//
        while(m--)
        {
            scanf("%d",&k);
            if(k<=p+1) printf("%d\n",k-1);
            else printf("%d\n",(k-p-1)*2+p);
        }

    }
    return 0;
}

 

 

 posted on 2013-08-20 21:13  ∑求和  阅读(340)  评论(0编辑  收藏  举报