蓝桥杯训练题1438: [蓝桥杯][2013年第四届真题]大臣的旅费【(bfs或dfs)+(vector+pair记录图的结点和边的权值)】

题目链接:

https://www.dotcpp.com/oj/problem1438.html

题目大意:

蓝桥杯训练题1438: [蓝桥杯][2013年第四届真题]大臣的旅费【(bfs或dfs)+(vector+pair记录图的结点和边的权值)】_第1张图片蓝桥杯训练题1438: [蓝桥杯][2013年第四届真题]大臣的旅费【(bfs或dfs)+(vector+pair记录图的结点和边的权值)】_第2张图片

思路:

①首先呢,就是利用bfs或者是dfs随便从一个点出发,然后找到一条路径总和的值最大的终点。
②然后呢再是用上面所找到的终点为起点再进行bfs或者dfs查找,这次记录的终点的值就是真正的最长路径值了。
③最长的路径值(也就是走的距离km)与路费的关系是等差数列的前n项和的关系。
(后面会有推导)

说一下为什么要用两次bfs或者是dfs呢?比如说题目这个数据:
5
1 2 2
1 3 1
2 4 5
2 5 4
画出来的图是这样的:
蓝桥杯训练题1438: [蓝桥杯][2013年第四届真题]大臣的旅费【(bfs或dfs)+(vector+pair记录图的结点和边的权值)】_第3张图片
假设说我们从3号点进行查找,我们能够找到的最长路径值的路径就是:
3->1->2->4对应的路径值是1+2+5=8,
而我们仔细观察发现最大的路径值是4+5=9,并不是8.
所以我们记录下来4(作为第一次找到的最长路径的终点结点),再一次以4为起点进行查找,就能找到最长路径了4->2->5对应路径值为4+5=9.

接下来解释下:路径值和价钱的关系

题目给的关系是:在走第x千米到第x+1千米这一千米中(x是整数),他花费的路费是x+10这么多。也就是说走1千米花费11,走2千米要花费23。

我们可以观察出:这是一个等差数列的前n项和,等差d=1,a1=11
根据等差数列的公式:
a1=11,
an=a1+(n-1)*d
前n项和:(a1+an)×n/2
带入化简可得:Sn=(n2+21×n)/2

下面说一下这个题中用到储存图的储存结构:

vector<pair<int,int> > vec[maxn];
//上面这个就是可以用来存储图的边的情况,首先单个:
//vector vec[maxn];就可以记录边两边的结点。
//加入pair就是为了能够顺便将边的权值存储进来

//这样的储存结构存储方式如下:
		vec[from].push_back(make_pair(to,dist));
		vec[to].push_back(make_pair(from,dist));
//利用make_pair()函数进行pair的初试赋值

//提取数据如下:
vec[p.n][i].first//pair提取数据用.first和.second分别来提取两个数据
vec[p.n][i].second//这里的.first指的就是这边指向的下一个结点,
//.second指的就是这个边的权值
//如:一条边:2 3 4
//p.n指的就是2,
//.first指的就是3
//.second指的就是 4

AC代码:

DFS++(vector+pair记录图的结点和边的权值):

#include 

using namespace std;

const int maxn = 100005;
int n;

vector<pair<int,int> > vec[maxn];//存入边和边对应的权值 

int gone[maxn];//记录已经走过的城市 
int maxlength;//记录最长的距离
int finish;

int dfs(int sx,int sum){
	
	if(sum>maxlength){
		maxlength = sum;
		finish = sx;
	}
	
	
	for(int i = 0;i < vec[sx].size();i++){
		if(gone[vec[sx][i].first] == 0){
			gone[sx] = 1;
			sum += vec[sx][i].second;
			
			dfs(vec[sx][i].first,sum);
			
			sum -= vec[sx][i].second;
			gone[sx] = 0;
			
		}
	}
	
} 



int main(){
	
	int from,to,dist;
	int ans;//算出最后花费的路费 
	cin>>n;
	for(int i = 0;i < n-1;i++){
		cin>>from>>to>>dist;
		vec[from].push_back(make_pair(to,dist));
		vec[to].push_back(make_pair(from,dist));
	}
	//第一遍dfs找出能找到最大路径值的起点 
	memset(gone,0,sizeof(gone));
	finish = 0;
	maxlength = 0;
	dfs(from,0);
//	cout<<"finish:"<
	
	
	//第二遍dfs从上面找出的起点出发去找最大路径值 
	memset(gone,0,sizeof(gone));
	maxlength = 0;
	dfs(finish,0);
	ans = (maxlength*maxlength+21*maxlength)/2; 
	
	cout<<ans<<endl;
	return 0;
}

BFS++(vector+pair记录图的结点和边的权值):

#include 

using namespace std;


const int maxn = 100005;
vector<pair<int,int> > vec[maxn];
int n;
int maxlength;//记录最大长度
int finish;//记录能找出最大路径值的起点 

int vis[maxn];//标记是否已经走过 

struct node{
	int n;//记录的当前的结点 
	int length;
};



void bfs(int sx,int len){
	
	queue<node> Q;
	node q;
	q.n = sx;
	q.length = len;
	
	Q.push(q);

	while(!Q.empty()){
		node p = Q.front();
		vis[p.n] = 1;
		if(p.length>maxlength){
			maxlength = p.length;
			finish = p.n; 
		}
		Q.pop();
		for(int i = 0;i < vec[p.n].size();i++){
			
			node k;
			
			if(vis[vec[p.n][i].first] == 0){
				
				k.n = vec[p.n][i].first;
				
				k.length = p.length + vec[p.n][i].second;
				
				Q.push(k);
			}
		}
	}
	
}


int main(){
	int from,to,dist;
	int ans;
	cin>>n;
	for(int i = 0;i < n-1;i++){
		cin>>from>>to>>dist;
		vec[from].push_back(make_pair(to,dist));
		vec[to].push_back(make_pair(from,dist));
	}
	
	//第一遍找出最大路径值的起点 
	memset(vis,0,sizeof(vis));
	maxlength = 0;
	finish = 0;
	bfs(from,0);
	
	//第二遍找出最大路径值 
	
	memset(vis,0,sizeof(vis));
	maxlength = 0;
	bfs(finish,0);
	
	ans = (maxlength*maxlength+21*maxlength)/2;
	
	cout<<ans<<endl;
//	cout<<"maxlength:"<
	
	return 0;
} 

你可能感兴趣的:(蓝桥杯训练题1438: [蓝桥杯][2013年第四届真题]大臣的旅费【(bfs或dfs)+(vector+pair记录图的结点和边的权值)】)