SDUT OJ 3045 迷之图论 (树的直径)

题目地址:SDUT OJ 3045

这题比赛的时候想的差不多。。但是总是觉得不对。。写了一次就没再写,然后删了。。当时没想到的是第二次求出来的就是最长链。。当时想到的两次bfs找最大值(这一种方法其实结果也对。。TAT。。),还有找到点后在回溯减去重点等等。。但总觉得好像都不太对。。。赛后才知道这题原来是树的直径。。。。。牡丹江区域现场赛的时候遇到过,不过赛后也没看。。。

找树的直径的方法其实就是先任取一点进行bfs,找到最远的一点,这时最远的一点肯定是最长链端点之一,然后再从这一最远点开始bfs,这时另一个端点就找到了,长度就是bfs的深度。

看的其他地方的证明如下:

关键在于证明第一次遍历的正确性,也就是对于任意点u,距离它最远的点v一定是最长路的一端。

如果u在最长路上,那么v一定是最长路的一端。可以用反证法:假设v不是最长路的一端,则存在另一点v’使得(u→v’)是最长路的一部分,于是len(u→v’) > len(u→v)。但这与条件“v是距u最远的点”矛盾。

如果u不在最长路上,则u到其距最远点v的路与最长路一定有一交点c,且(c→v)与最长路的后半段重合(why?),即v一定是最长路的一端。

代码如下:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <queue>
#include <map>
#include <set>
#include <algorithm>

using namespace std;
#define LL __int64
const int INF=0x3f3f3f3f;
int head[110001], cnt, vis[110001], pos, d;
struct node {
        int u, v, next;
} edge[210001];
void add(int u, int v)
{
        edge[cnt].v=v;
        edge[cnt].next=head[u];
        head[u]=cnt++;
}
struct node1 {
        int n, ans;
};
void bfs(int source)
{
        memset(vis,0,sizeof(vis));
        vis[source]=1;
        node1 f1, f2;
        queue<node1>q;
        f1.n=source;
        f1.ans=0;
        q.push(f1);
        while(!q.empty()) {
                f1=q.front();
                pos=f1.n;
                d=f1.ans;
                q.pop();
                int u=f1.n;
                for(int i=head[u]; i!=-1; i=edge[i].next) {
                        int v=edge[i].v;
                        if(!vis[v]) {
                                f2.n=v;
                                f2.ans=f1.ans+1;
                                vis[v]=1;
                                q.push(f2);
                        }
                }
        }
}
int main()
{
        int n, i, j, u, v;
        while(scanf("%d",&n)!=EOF) {
                if(n==1) {
                        printf("1\n");
                        continue ;
                }
                memset(head,-1,sizeof(head));
                cnt=0;
                for(i=0; i<n-1; i++) {
                        scanf("%d%d",&u,&v);
                        add(u,v);
                        add(v,u);
                }
                bfs(1);
                bfs(pos);
                printf("%d\n",d+1);
        }
        return 0;
}
时间: 2024-10-09 12:05:50

SDUT OJ 3045 迷之图论 (树的直径)的相关文章

SDUTOJ 3045 迷之图论 搜索

找树的直径的方法其实就是先任取一点进行bfs,找到最远的一点,这时最远的一点肯定是最长链端点之一,然后再从这一最远点开始bfs,这时另一个端点就找到了,长度就是bfs的深度. 这道题目看了别人的才猛然想到对啊,你照的点的最长肯定在你要找的最长的上面.开始还以为是树对树有种莫名其妙的恐惧感.... Description FF是图论高手,所以我要出图论且不出流问题. 给出一个树,求树的最长链的长度. Input 多组输入.每组输入的第一行为n(1 <= n <= 100000),代表节点个数,节

SDUT 3045-迷之图论(树的直径)

题目链接:点击打开链接 对于一棵无向树: 任意点出发,找到最远点,设这个为起点,从起点出发找到最远点为终点 这条路就是直径 两次BFS: #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <string> #include <cctype> #include <vector> #include &l

SDUT OJ 2413 数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历

#include<iostream> #include<memory.h> using namespace std; int p[1010][1010]; int visit[110]; int c[1010]; int a=0; int b=1; int k; int t; void bfs(int n) { a++; for(int i=0;i<k;i++) { if(p[n][i]==1&&visit[i]==0) { c[b++]=i; visit[i

【SDUT OJ 2610】 Boring Counting(主席树)

[SDUT OJ 2610] Boring Counting(主席树) Boring Counting Time Limit: 3000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 In this problem you are given a number sequence P consisting of N integer and Pi is the ith element in the sequence. Now you task is to ans

SDUT OJ -2892 A

A Time Limit: 60ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 给出n(1<= n && n <= 2*10^6)个字符串,每个字符串只包含小写英文字母,且最多有五个.问这n个字符串中出现次数最多的有多少个. 输入 单组输入.第一行输入一个数字n,接下来n行,每行包含一个字符串. 输出 输出一个数字代表答案. 示例输入 5 aba abb w aba z 示例输出 2 提示 字段树,模板题 #include <iost

sdut3045迷之图论--(多叉树求最长链)

迷之图论 Time Limit: 1000MS Memory limit: 65536K 题目描述 FF是图论高手,所以我要出图论且不出流问题. 给出一个树,求树的最长链的长度. 输入 多组输入.每组输入的第一行为n(1 <= n <= 100000),代表节点个数,节点编号从1 到n,接下来的n-1行,每行两个正整数u,v,代表u,v之间有一条边相连.保证每组数据都是一棵树. 输出 对于每组数据,输出一个正整数代表答案. 示例输入 121 2 示例输出 12 提示 来源 zmx dfs搜索

SDUT OJ 1704 数字统计问题

SDUT OJ 1704 数字统计问题 博客原文地址:http://blog.csdn.net/xuechelingxiao/article/details/40930259 昨天晚上学弟问了OJ上这个题,群里说不清楚,就写个解题报告吧. 题目大意: 中文题目,就不翻译了-.- 解题思路: 不知道算不算一个典型的数位DP,反正有点那个意思,感觉确实也可以用记忆话搜索,两个差不多的意思. 我找了一下,这个问题好像是算法设计与实验题解上面的一道题,别的OJ上没有,所以就在自己OJ上做了. 大体的思路

图论-树的最大路

历届试题 大臣的旅费 时间限制:1.0s   内存限制:256.0MB 问题描述 很久以前,T王国空前繁荣.为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市. 为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达.同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的. J是T国重要大臣,他巡查于各大城市之间,体察民情.所以,从一个城市马不停蹄地到另一个城市成了J最常做的事情.他有一个钱袋,用于

Light OJ 1114 Easily Readable 字典树

题目来源:Light OJ 1114 Easily Readable 题意:求一个句子有多少种组成方案 只要满足每个单词的首尾字符一样 中间顺序可以变化 思路:每个单词除了首尾 中间的字符排序 然后插入字典树 记录每个单词的数量 输入一个句子 每个单词也排序之后查找 根据乘法原理 答案就是每个单词的数量之积 #include <iostream> #include <cstring> #include <cstdio> #include <algorithm>