POJ 1985 Cow Marathon(两次BFS求树的直径(最长路))

本文介绍了一种在给定树结构中查找最远两点间的路径长度的方法,通过两次广度优先搜索(BFS)策略实现。这种方法在解决实际问题时展现出了较高的效率,特别适用于大规模树形结构的数据分析。

Cow Marathon
Time Limit: 2000MS Memory Limit: 30000K
Total Submissions: 0 Accepted: 0
Case Time Limit: 1000MS

Description

After hearing about the epidemic of obesity in the USA, Farmer John wants his cows to get more exercise, so he has committed to create a bovine marathon for his cows to run. The marathon route will include a pair of farms and a path comprised of a sequence of roads between them. Since FJ wants the cows to get as much exercise as possible he wants to find the two farms on his map that are the farthest apart from each other (distance being measured in terms of total length of road on the path between the two farms). Help him determine the distances between this farthest pair of farms. 
Farmer John's pastoral neighborhood has N farms (2 <= N <= 40,000), usually numbered/labeled 1..N. A series of M (1 <= M < 40,000) vertical and horizontal roads each of varying lengths (1 <= length <= 1000) connect the farms. A map of these farms might look something like the illustration below in which farms are labeled F1..F7 for clarity and lengths between connected farms are shown as (n): 
           F1 --- (13) ---- F6 --- (9) ----- F3

            |                                 |

           (3)                                |

            |                                (7)

           F4 --- (20) -------- F2            |

            |                                 |

           (2)                               F5

            | 

           F7 

Input

* Line 1: Two space-separated integers: N and M



* Lines 2..M+1: Each line contains four space-separated entities, F1,

        F2, L, and D that describe a road. F1 and F2 are numbers of

        two farms connected by a road, L is its length, and D is a

        character that is either 'N', 'E', 'S', or 'W' giving the

        direction of the road from F1 to F2.

Output

* Line 1: An integer giving the distance between the farthest pair of farms. 

Sample Input

7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S

Sample Output

52

Hint

The longest marathon runs from farm 2 via roads 4, 1, 6 and 3 to farm 5 and is of length 20+3+13+9+7=52. 
/************************************************************************/

题意:给你一棵n个结点m条边的树,求树的直径,即树上相隔最远的两点的距离(最长路)

解题思路:树的直径是指树的最长简单路。如果我们直接找最长路是比较困难的,因为两点都没有确定,那么势必需要暴力枚举任意两点求距离,这样耗时比较严重,故采取下述方法来求树的直接。
求法:两遍BFS :先任选一个起点BFS找到最长路的终点,再从终点进行BFS,则第二次BFS找到的最长路即为树的直径;

我们现在假设如图红色部分为该树的直径,因为我们不知道哪些点在直径上,故我们任意挑一点,两种情况:在直径上,如u1;不在直径上,如u0。在直径上时,毋庸置疑,u1s必定是从u1出发的最长路,反证不是的话,那么必定存在一条比u1s长的路,假设为u1x,那么树的直径应该为vu1+u1x=vx,而不是vs;如果挑选的点不在直线上时,如u0,同理可证。
   原理:设起点为u,第一次BFS找到的终点v一定是树的直径的一个端点
   
证明: 1) 如果u是直径上的点,则v显然是直径的终点(因为如果v不是的话,则必定存在另一个点w使得u到w的距离更长,这与BFS找到了v矛盾)
             2) 如果u不是直径上的点,则u到v必然于树的直径相交(反证),那么交点到v必然就是直径的后半段了

所以v一定是直径的一个端点,所以从v进行BFS得到的一定是直径长度
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<stdlib.h>
#include<cmath>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N = 40005;
const int inf = 1000000000;
const int mod = 2009;
struct edge
{
    int t,v,next;
}e[2*N];
struct node
{
    int d,u;
    node(){}
    node(int u0,int d0):u(u0),d(d0){}
    bool operator < (const node &a) const
    {
       return d>a.d;//最小值优先
    }
};
int h[N],p,Max,k;
bool v[N];
void add_edge(int u,int v,int c)
{
    e[p].t=v;
    e[p].v=c;
    e[p].next=h[u];
    h[u]=p++;
}
int bfs(int x)
{
    priority_queue<node> q;
    q.push(node(x,0));
    Max=k=0;
    memset(v,false,sizeof(v));
    v[x]=true;
    while(!q.empty())
    {
        node u=q.top();
        q.pop();
        for(int i=h[u.u];i+1;i=e[i].next)
            if(!v[e[i].t])
            {
                v[e[i].t]=true;
                q.push(node(e[i].t,u.d+e[i].v));
            }
        if(u.d>Max)
            Max=u.d,k=u.u;
    }
    return k;
}
int main()
{
    int n,m,i,a,b,c;
    char ch;
    while(~scanf("%d%d",&n,&m))
    {
        memset(h,-1,sizeof(h));
        for(p=i=0;i<m;i++)
        {
            scanf("%d%d%d %c",&a,&b,&c,&ch);
            add_edge(a,b,c);
            add_edge(b,a,c);
        }
        bfs(bfs(1));
        printf("%d\n",Max);
    }
	return 0;
}
菜鸟成长记
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值