今天一个师哥讲了图的进阶,感觉师哥讲的很好,有很多启发性的问题。
其中一个问题是图的搜索和图的遍历有什么区别?
最大的区别就是遍历只需要扫描一遍图。
而每一次搜索可能都需要搜索全图的时间复杂度。
所以如果拿没有优化的搜索去暴力的话,每一次搜索都需要遍历一遍图。这样有很大的可能性是会T的。
接下来讲讲 HDU - 2196 这道题,这道题如果直接暴力搜索,以每个点作为根节点的话,很有可能会T,所以需要用到树的直径的性质。
树的直径的定义:树中所有最短路径的最大值。
所以树上任意一点对应的距离最远端点一定是 树的直径的某个端点。
所以这题只需要三遍dfs就可以做出来了。
第一遍找出树的一个直径端点a。
第二遍计算其余所有点到a的距离,并找出树的直径的另一个端点b。
第三遍计算其余所有点到端点b的距离。
树上任意一点对应的距离的最大值一定是到某一个端点的距离。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
#define maxn 10005
struct edge
{
int to;
int next;
int w;
}edge[maxn*2];
int head[maxn*2];
int n;
int rt;
int drt[maxn];
int d1[maxn];
int d2[maxn];
int total;
void add(int u,int v,int l)
{
edge[total].to = v;
edge[total].w = l;
edge[total].next = head[u];
head[u] = total;
total++;
edge[total].to = u;
edge[total].w = l;
edge[total].next = head[v];
head[v] = total;
total++;
}
void dfs(int u,int fa,int d[]) //从u点遍历到根节点 并将结果存储在数组中
{
for(int i= head[u];i!=-1;i= edge[i].next)
{
int v = edge[i].to;
if(v!=fa)
{
d[v] = d[u]+edge[i].w;
if(d[rt]<d[v])rt = v;
dfs(v,u,d);
}
}
}
int main()
{
int x,y;
while(cin>>n)
{
total=0;
memset(head,-1,sizeof(head));
for(int i=2;i<=n;i++)
{
cin>>x>>y;
add(i,x,y);
}
memset(drt,0,sizeof(drt));
memset(d1,0,sizeof(d1));
memset(d2,0,sizeof(d2));
rt=1;
dfs(1,-1,drt);
dfs(rt,-1,d1);
dfs(rt,-1,d2);
for(int i=1;i<=n;i++)
{
cout<<max(d1[i],d2[i])<<endl;
}
}
return 0;
}
一点注意:
用邻接表存储的图,bfs和dfs的时间复杂度均为 o(v+e) 。