POJ1383

来源:互联网 发布:奥凯软件 编辑:程序博客网 时间:2024/06/05 18:43

树的直径。开始写了一个dfs的然后RT了。于是后来改成写两个bfs,然后就过了。思路,两次bfs,第一次随便从哪一个节点开始找到一个距离它最远的节点。然后第二次bfs从找到的最远的节点开始找最远的路,即为树的直径。这里有一个很好的证明,从别人博客看来的:

<转>BFS找到的最长路即为树的直径;

原理: 设起点为u,第一次BFS找到的终点v一定是树的直径的一个端点
证明: 1) 如果u 是直径上的点,则v显然是直径的终点(因为如果v不是的话,则必定存在另一个点w使得u到w的距离更长,则于BFS找到了v矛盾)
2) 如果u不是直径上的点,则u到v必然于树的直径相交(反证),那么交点到v 必然就是直径的后半段了

所以v一定是直径的一个端点,所以从v进行BFS得到的一定是直径长度

上代码:

#include<cstdio>
#include<cstring>
using namespace std;
char map[1010][1010];
int vis[1001][1001];
int q[1000010][2];
int ansi,ansj,ans;
int step[1000010];
void bfs1(int i1,int j1){
int h=0,r=1;
vis[i1][j1]=1;
q[0][0]=i1;
q[0][1]=j1;
step[0]=0;
while(h<r){
//printf("wa\n");
int i,j;
ansi=i=q[h][0];
ansj=j=q[h][1];
ans=step[h];
if(map[i-1][j]=='.' && !vis[i-1][j]){
q[r][0]=i-1;q[r][1]=j;
vis[i-1][j]=1;
step[r++]=step[h]+1;
}
if(map[i+1][j]=='.' && !vis[i+1][j]){
q[r][0]=i+1;q[r][1]=j;
vis[i+1][j]=1;
step[r++]=step[h]+1;
}
if(map[i][j+1]=='.' && !vis[i][j+1]){
q[r][0]=i;q[r][1]=j+1;
vis[i][j+1]=1;
step[r++]=step[h]+1;
}
if(map[i][j-1]=='.' && !vis[i][j-1]){
q[r][0]=i;q[r][1]=j-1;
vis[i][j-1]=1;
step[r++]=step[h]+1;
}
h++;
}
}
main(){
int c,r,t,i1,j1;
scanf("%d",&t);
while(t--){
scanf("%d%d",&r,&c);
i1=j1=0;
for(int i=1;i<=c;i++){
getchar();
for(int j=1;j<=r;j++){
scanf("%c",&map[i][j]);
if(i1==0 && map[i][j]=='.'){
i1=i;j1=j;
}
}
}
ansi=0;ansj=0;
ans=0;
memset(vis,0,sizeof(vis));
// printf("%d %d\n",i1,j1);
bfs1(i1,j1);
// printf("%d\n",ans);
ans=0; //printf("%d %d\n",ansi,ansj);
memset(vis,0,sizeof(vis));
bfs1(ansi,ansj);
printf("Maximum rope length is %d.\n",ans);

}
}

原创粉丝点击