蓝桥杯 历届试题 大臣的旅费:两遍DFS/BFS (已AC)

问题描述

很久以前,T王国空前繁荣。为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。

为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的。

J是T国重要大臣,他巡查于各大城市之间,体察民情。所以,从一个城市马不停蹄地到另一个城市成了J最常做的事情。他有一个钱袋,用于存放往来城市间的路费。

聪明的J发现,如果不在某个城市停下来修整,在连续行进过程中,他所花的路费与他已走过的距离有关,在走第x千米到第x+1千米这一千米中(x是整数),他花费的路费是x+10这么多。也就是说走1千米花费11,走2千米要花费23。

J大臣想知道:他从某一个城市出发,中间不休息,到达另一个城市,所有可能花费的路费中最多是多少呢?

输入格式

输入的第一行包含一个整数n,表示包括首都在内的T王国的城市数

城市从1开始依次编号,1号城市为首都。

接下来n-1行,描述T国的高速路(T国的高速路一定是n-1条)

每行三个整数Pi, Qi, Di,表示城市Pi和城市Qi之间有一条高速路,长度为Di千米。

输出格式

输出一个整数,表示大臣J最多花费的路费是多少。

样例输入1
5
1 2 2
1 3 1
2 4 5
2 5 4
样例输出1
135
输出格式

大臣J从城市4到城市5要花费135的路费。


根据性质来看,这是一棵树找最大权值路径问题,和求一棵树的直径是一样的。

一开始不知道一个理论走了很多弯路。

由于数据n有一个10000的我们不可能开一个10000*10000的数组,你可以用结构体来表示边之间的关系,我是用了两个map

map<int,vector<int>> t,第一个int表示节点编号,第二个vector用来盛放与这个节点又直接边相连的节点。

map<pair<int,int>,int> dist pair二元组用来盛放两节点编号,后面用来盛放两节点距离

例如输入 1 2 2,即1号城市与2号城市之间距离为2

那么应该这样存储这条信息。

t[1].push_back(2);

t[2].push_back(1);

dist[make_pair(1,2)]=2;

至于map,vector怎么用,可以百度一下

一开始不知道两遍DFS/BFS两遍就可以,把所有节点都遍历了一遍,结果都是75分

先贴75分代码:

1.DFS:

#include <iostream>
#include <map>
#include <vector>
#include <cstring>
using namespace std;
map<int,vector<int> > t;
map<pair<int,int>,int> dis;
int visited[10001];
int mdis=0;
void DFS(int i,int d)
{
	if(!visited[i])
	{
		visited[i]=1;
		if(d>mdis)
			mdis=d;
		for(int j=0;j<t[i].size();j++)
		{
			if(!visited[t[i][j]])//t[i][j]表示t[i]数组中第j个元素
			{
				pair<int,int> tmp(i,t[i][j]);
				DFS(t[i][j],d+dis[tmp]);
			}
		}		
	}
}
int main()
{
	int n,a,b,d,cost=0;
	cin>>n;
	for(int i=0;i<n-1;i++)
	{
		cin>>a>>b>>d;
		t[a].push_back(b);
		t[b].push_back(a);
		dis[make_pair(a,b)]=d;
		dis[make_pair(b,a)]=d;
	}
	for(int i=1;i<=n;i++)
	{
		memset(visited,0,sizeof(visited));
		DFS(i,0);
	}
	for(int i=1;i<=mdis;i++)
		cost+=(10+i);
	cout<<cost<<endl;
	return 0;
}


2.BFS

#include <iostream>
#include <map>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
map<int,vector<int> > t;
map<pair<int,int>,int> dist;
queue<int> q;
int visited[10001];
int dis[10001];
int mdis=0,n,pos;
int BFS(int x)
{
	int tmp,Max=0;
	q.push(x);
	visited[x]=1;
	while(!q.empty())
	{
		tmp=q.front();
		for(int i=0;i<t[tmp].size();i++)
			if(!visited[t[tmp][i]])
			{
				pair<int,int> dit(tmp,t[tmp][i]);
				q.push(t[tmp][i]);
				visited[t[tmp][i]]=1;
				dis[t[tmp][i]]=dis[tmp]+dist[dit];//dis用来放x节点到t[tmp][i]节点距离
			}			
		q.pop();
	}
	for(int i=1;i<=n;i++)//找出从x出发距离最大的路径
		if(Max<dis[i])
		{
			Max=dis[i];
			pos=i;
		}
	return Max;	
}
int main()
{
	int a,b,d,cost=0,tmp;
	cin>>n;
	for(int i=0;i<n-1;i++)
	{
		cin>>a>>b>>d;
		t[a].push_back(b);
		t[b].push_back(a);
		dist[make_pair(a,b)]=d;
		dist[make_pair(b,a)]=d;
	}
	for(int i=1;i<=n;i++)
	{
		memset(visited,0,sizeof(visited));
		memset(dis,0,sizeof(dis));
		tmp=BFS(i);
		if(tmp>mdis)
			mdis=tmp;
	}
	for(int i=1;i<=mdis;i++)
		cost+=(10+i);
	cout<<cost<<endl;
	return 0;
}

其实我们想想,如果我们知道根节点是哪一个的话,是不是就简单了很多

就像求树的直径(树的直径:是树中所有最短路径长度中的最大值)那样,两遍BFS/DFS。

在树的直径中,我们先遍历一遍,随便找一个节点为根节点,找出最长路(长度为数的高度)的终点即叶节点,那么,这个叶节点一定是树的直径的一个端点。我们只需再以这个叶节点为根节点遍历一遍,再找到一个叶子节点,这两个叶子节点间的路径就是树的直径的路径。

同样的:

拿这个题来说:

第一遍遍历,随便找一个点i遍历一遍,找出一个距离i最远的点x,则x一定是最终我们要找的那条路径的一个端点

第二次只需要从x这个点遍历一遍找出距离x最远的点y,x->y的花费即为我们要求得结果

AC代码:

1.DFS

#include <iostream>
#include <map>
#include <vector>
#include <cstring>
using namespace std;
map<int,vector<int> > t;
map<pair<int,int>,int> dis;
int visited[10001];
int mdis=0,pos;
void DFS(int i,int d)
{
	if(!visited[i])
	{
		visited[i]=1;
		if(d>mdis)
		{
			pos=i;
			mdis=d;			
		} 
		for(int j=0;j<t[i].size();j++)
			if(!visited[t[i][j]])
			{
				pair<int,int> tmp(i,t[i][j]);
				DFS(t[i][j],d+dis[tmp]);
			}	
	}
}
int main()
{
	int n,a,b,d,cost=0;
	cin>>n;
	for(int i=0;i<n-1;i++)
	{
		cin>>a>>b>>d;
		t[a].push_back(b);
		t[b].push_back(a);
		dis[make_pair(a,b)]=d;
		dis[make_pair(b,a)]=d;
	}
	memset(visited,0,sizeof(visited));//一定不要忘记两次置零
	DFS(1,0);//找到一个端点
	memset(visited,0,sizeof(visited));
	DFS(pos,0);
	for(int i=1;i<=mdis;i++)
		cost+=(10+i);
	cout<<cost<<endl;
	return 0;
}

2.BFS:

#include <iostream>  
#include <map>  
#include <vector>  
#include <cstring>  
#include <queue>  
using namespace std;  
map<int,vector<int> > t;  
map<pair<int,int>,int> dist;  
queue<int> q;  
int visited[10001];  
int dis[10001];  
int mdis=0,n,pos;  
int BFS(int x)  
{  
    int tmp,Max=0;  
    q.push(x);  
    visited[x]=1;  
    while(!q.empty())  
    {  
        tmp=q.front();  
        for(int i=0;i<t[tmp].size();i++)  
            if(!visited[t[tmp][i]])  
            {  
                pair<int,int> dit(tmp,t[tmp][i]);  
                q.push(t[tmp][i]);  
                visited[t[tmp][i]]=1;  
                dis[t[tmp][i]]=dis[tmp]+dist[dit];  
            }             
        q.pop();  
    }  
	if(Max<dis[i])  
        {  
            Max=dis[i];  
            pos=i;  
        }  
    return Max;   
}  
int main()  
{  
    int a,b,d,cost=0,tmp;  
    cin>>n;  
    for(int i=0;i<n-1;i++)  
    {  
        cin>>a>>b>>d;  
        t[a].push_back(b);  
        t[b].push_back(a);  
        dist[make_pair(a,b)]=d;  
        dist[make_pair(b,a)]=d;  
    }  
    memset(visited,0,sizeof(visited));  
    memset(dis,0,sizeof(dis));  
    BFS(1);  
    memset(visited,0,sizeof(visited));  //一定不要忘记两遍置零
    memset(dis,0,sizeof(dis));  
    mdis=BFS(pos);  
    for(int i=1;i<=mdis;i++)  
        cost+=(10+i);  
    cout<<cost<<endl;  
    return 0;  
}  


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值