1. 程式人生 > >POJ 1985 Cow Marathon(兩次BFS求樹的直徑(最長路))

POJ 1985 Cow Marathon(兩次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;
}
菜鳥成長記