奇怪的Andy,奇怪的旅行(无向图——邻接链表)

题目:

在地球上有一个奇怪的国家,这个国家有 n 个城市,但却只有 n−1 条道路,但是每个城市之间都可以互相到达

某天 Andy 来到了这个国家,但是他以前没有出去旅游,真是个奇怪的人呢。他来到了这个国家进行一次旅行,想花尽量少的钱走过更多的城市,

不想走回头路,因为这样会多花钱,真是个抠门的人呢。已知的是 Andy 可以任意选一个城市作为他旅行的起点。现在他找到你,他想知道他最多能走过多少个城市

【输入格式】

第一行一个整数 n 表示这个国家的城市数量。

接下来 n−1行,每一行有两个整数 (u,v) 表示u,v之间有一条边。

tips: 1<=n<=100000

【输出格式】

输出一个数字,表示 Andy最多能走过多少个城市

【样例输入】

3

1 2

1 3

【样例输出】

3

tips: Andy可以按照城市2 −> 城市1 −> 城市3的路线进行旅行。

分析:

题意意思是,给n个点,共有n-1条边,且保证每个城市都能相互抵达====>推出结论,该城市构成的图无环形成(画一画就知道了),所以不需要考虑环的问题。

因为可以相互抵达,所以这是一个无向图。

题目需要我们求图的最长的路径

image-20211228220912480image-20211228220957360

1.解题思路

2.如何实现思路

3.介绍方法中使用的数据结构

4.源代码

下面以该例子讲解题解

image-20211228221637366

1.无向图求最大路径解法(有向图中无效)

第一步:任意选取一个结点start,然后从该节点出发,求能达到的最大路径–>进行一次深度搜索,得到距离最远的城市end(可能有多个,但题目不要求输入所有答案,所以只记录一个即可,结果都是一样的);

第二步:注意:这一步需要从end结点出发,重复第一步。

比如:

选取了结点1,从1出发,那么能达到的最远的结点是4,经过的城市一共是3个.

然后从4出发,能到达的最远节点是2,经过的城市一共是4个.

答案是4。

不证明了,百度一下,或者画两个其他例子的图自己试试说服自己。

2.如何实现思路

听说大家树学得很棒。可以将这个无环图看成树。在我们选取一个节点的时候,将这个结点当成一个根节点,与它相邻的结点当成孩子结点。那么问题转换成了求树的深度。

以结点1为根节点的树

image-20211228223247143

以结点4为根节点的树

image-20211228223414788

3.介绍方法中使用的数据结构、

对于每一个节点而言,它的孩子结点数量都是不一样的,比如上图中有1,也有2.

这里使用vector来对每一个结点,存储他的孩子节点。节省内存空间

vector:C++ 的一个STL容器

  • 类似于数组,可以直接使用下标访问。
  • 动态的增加和删除,长度也会变化
//定义一个能存储int类型的动态数组,初始容量为n,但不会固定,默认值为0
vector<int>  v(n); 
int a[n];  //固定n长度

int len=v.size();  //求长度,len=n    
v[0]=22;   //将22赋值给v下标为0 此时v={22,n-1个0} len=n 
v.push_back(33); //将33插入到v的队尾 此时v={22,n-1个0,33} len=n +1
v.pop_back();   //删除最后一个,此时v={22,n-1个0} len=n

更具体 百度

4.源码

#include <iostream>
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include<vector>
#include<map>
#include<math.h>
using namespace std;
/**
 * 
 **/
int maxNum=0;  //最多能走过城市的数量
int start=1;   //起点

void dfs(vector<vector<int> > graph,int num,int depth,int flag[]);

int main(){
    int n;
    scanf("%d",&n);
    vector<vector<int> > graph(n+1);//存各个点
    int flag[n+1]={0};//用来标记该点是否遍历过
    int a,b;
    //建立与该点相连的城市
    for(int i=0;i<n-1;i++){
        scanf("%d %d",&a,&b);
        graph[a].push_back(b);//插入
        graph[b].push_back(a);//插入
    }
    /**
     *输出每个点与哪一个点相连 
     */
    for(int i=1;i<=n;i++){
        vector<int> v=graph[i];
        int len =v.size();
        printf("与城市 %d 相邻的城市有: ",i);
        for(int j=0;j<len;j++){
            printf(" %d",v[j]);
        }
        printf("\n");
    }
    //任意选一个点,这里默认设置选城市1,进行dfs,得到以该点为起点的的最大路径
    dfs(graph,start,0,flag);//参数 2:城市起点  3:去过的城市数量总和
    printf("起点为:%d\n",start);  

    //重置一下第一次的记录
    maxNum=0;
    memset(flag, 0, sizeof(flag));//数组清0

    //以该点位起点,再进行一次dfs.得到答案。
    dfs(graph,start,0,flag);
    printf("终点为:%d\n",start);
    printf("Andy最多能走过 %d 个城市\n",maxNum);
    system("pause");
    return 0;
}

void dfs(vector<vector<int> > graph,int num,int depth,int flag[]){
	if(depth>=maxNum){
	    start=num;
    }
    if(flag[num]==1){//已经遍历,跳过
        return;
    }
    depth++;
    maxNum=max(depth,maxNum);
    vector<int> v=graph[num];
    int len =v.size();
    flag[num]=1;
    for(int j=0;j<len;j++){
        if(flag[v[j]]!=1)  //遍历过的,跳过
        dfs(graph,v[j],depth,flag);
    }
}
  • 8
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值