樹的直徑是指樹的最長簡單路。求法: 兩遍BFS :先任選一個起點BFS找到最長路的終點,再從終點進行BFS,則第二次BFS找到的最長路即為樹的直徑;
原理: 設起點為u,第一次BFS找到的終點v一定是樹的直徑的一個端點
證明: 1) 如果u 是直徑上的點,則v顯然是直徑的終點(因為如果v不是的話,則必定存在另一個點w使得u到w的距離更長,則于BFS找到了v矛盾)
2) 如果u不是直徑上的點,則u到v必然于樹的直徑相交(反證),那么交點到v 必然就是直徑的后半段了
所以v一定是直徑的一個端點,所以從v進行BFS得到的一定是直徑長度
相關題目有TOJ1056,TOJ3517.
TOJ 1056(Labyrinth):
大意是一個由‘#’和'.'構成的迷宮,'.'表示可行,‘#’表示不可行,問可行的最長的路的長度是多少。
#include <cstdio>
#include <cstring>
#include <queue>
#define M 1002
using namespace std;
int r,c;
char map[M][M];
bool flag[M][M];
int move[4][2]={-1,0,1,0,0,-1,0,1}; // 分別表示上下左右
int maxt;
struct Node{
int x,y,num;
};
Node ans;
bool legal(int x,int y){ //判斷該點是否越界及是否可走
if(x >=0 && x < r && y>=0 && y < c &&map[x][y]=='.') return true;
return false;
}
void bfs(Node start){
memset(flag,false,sizeof(flag)); //初始所有點標記為false
flag[start.x][start.y] = true; //起點標記為true
queue<Node>f;
while(!f.empty()) f.pop(); //清空創建的隊列
Node m,n,tep;
int tx,ty,xx,yy;
int i,j,k,num;
f.push(start);
while(!f.empty()){ //如果隊列不為空
m = f.front(); //取出隊首元素
tx = m.x; ty = m.y; num = m.num;
if(num > maxt){ //如果該元素的長度大于maxt,更新maxt
maxt = num;
ans = m;
}
for(i = 0;i < 4; i++){ //以m為起點向4個方向BFS
xx = tx + move[i][0];
yy = ty + move[i][1];
if(!flag[xx][yy] && legal(xx,yy)){
flag[xx][yy] = true;
tep.x = xx;
tep.y = yy;
tep.num = num + 1;
f.push(tep);
if(num+1>maxt){ //如果有更大的則更新
maxt = num + 1;
ans = tep;
}
}
}
f.pop(); //彈出隊首元素
}
}
int main(){
int i,j,T;
Node start,end;
bool mark;
scanf("%d",&T);
while(T--){
scanf("%d%d",&c,&r);
mark = false; maxt = -1;
for(i = 0;i < r; i++)
scanf("%s",map[i]);
for(i = 0;i < r; i++){
for(j = 0;j < c; j++){
if(map[i][j]=='.'){ //任選一點BFS
start.x = i;
start.y = j;
start.num = 0;
bfs(start);
mark = true;
break;
}
}
if(mark) break;
}
maxt = -1;ans.num = 0; //此時ans一定是直徑的端點,將它設為起點
bfs(ans); //進行第二次BFS
printf("Maximum rope length is %d.\n",maxt);
}
}
TOJ3517(The longest athletic track):
題目給出了一棵生成樹,問這棵生成樹最長的路的長度是多少。
#include<iostream>
#include<queue>
#define INF 999999
#define M 2002
using namespace std;
int n;
int maxx;
int map[M][M],sum[M];
bool flag[M];
int bfs(int begin){
queue<int>f;
int i,m,k,key;
maxx=0;
memset(flag,false,sizeof(flag));
f.push(begin);
while(!f.empty()){
k=f.front();
for(i=1;i<=n;i++){
if(map[k][i]!=INF&&!flag[i]){
flag[i]=true;
f.push(i);
sum[i]=sum[k]+map[k][i];
if(sum[i]>maxx) { maxx=sum[i];key=i; }
}
}
f.pop();
}
return key;
}
int main()
{
int i,j,k,dis,key,cas;
scanf("%d",&cas);
while(cas--){
scanf("%d",&n);
for(i=1;i<n;i++)
for(j=i+1;j<=n;j++)
map[i][j]=map[j][i]=INF;
for(i=1;i<n;i++){
scanf("%d%d%d",&j,&k,&dis);
map[j][k]=map[k][j]=dis;
}
sum[1]=0;
key=bfs(1);
sum[key]=0;
key=bfs(key);
printf("%d\n",maxx);
}
//system("pause");
}