zoukankan      html  css  js  c++  java
  • 蓝桥杯2013年第四届真题 大臣的旅费

    蓝桥杯2013年第四届真题 大臣的旅费

    题意

    很久以前,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千米。

    n的规模在1e5

    输出

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

    解题思路

    其实这个题意就是想让我们求一个树的直径,求出输的直径来,最后在按照题目中说的所需金额的定义,其实公式就是$$s*10+(1+s)/2$$,其中s表示这个树直径的长度。

    我开始的做法是使用了最短路来解决的,先任意选一个点,比如是1,跑完最短路就可以知道距离1号城市的最远城市的编号t,然后下次就以这个t为出发点,再跑一遍最短路,那么距离t最远的距离就是我们需要距离了。但是这样有个问题,最短路算法的选择问题。

    因为n的规模在1e5,如果选择使用Dijkstra算法,那么使用邻接矩阵是超存储空间的,这个我也试了,只能开到1e4,因而得分不能得到全分,仅仅80分。但是使用优先队列改进的Dijkstra算法是可以的。

    下面给出代码。

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<string>
    #include<stack>
    #include<queue>
    #include<map>
    #include<set>
    #include<sstream>
    typedef long long ll;
    using namespace std;
    const double eps=1e-6;
    const int inf=0x3f3f3f3f;
    const int MAXN=1E5+7;
    int head[MAXN], cnt = 1;
    struct stut{
    	int to, w, next;
    }edge[MAXN];
    inline void addedge(int u, int v, int w){
    	edge[cnt].to = v; edge[cnt].w = w;
    	edge[cnt].next = head[u];
    	head[u] = cnt++;
    }
    
    struct Node{
    	int u, d;
    	friend bool operator < (const Node a, const Node b){
    		return a.d > b.d;
    	} 
    	Node(int a, int b){
    		u = a; d = b;
    	}
    }; 
    priority_queue<Node> que;
    int dis[MAXN];
    bool vis[MAXN];
    int n;
    void dij(int s){
    	for(int i=1; i<=n; i++){
    		dis[i] = inf;
    		vis[i] = false;
    	}
    	dis[s] = 0;
    	vis[s] = true;
    	Node tmp(s, 0);
    	que.push(tmp);
    	int u;
    	while(!que.empty()){
    		u = que.top().u;
    		que.pop();
    		vis[u] = true;
    		for(int i=head[u]; i>0; i=edge[i].next){
    			if(!vis[edge[i].to] && dis[edge[i].to]>dis[u]+edge[i].w){
    				dis[edge[i].to] = dis[u]+edge[i].w;
    				tmp.d=dis[edge[i].to];
    				tmp.u=edge[i].to;
    				que.push(tmp);
    			}
    		}
    	}
    }
    int main()
    {
    	scanf("%d", &n);
    	int u, v, w;
    	for(int i=1; i<n; i++){
    		scanf("%d%d%d", &u, &v, &w);
    		addedge(u, v, w);
    		addedge(v, u, w);
    	}
    	dij(1);
    	int s1, tmp = dis[1];
    	for(int i=1; i<=n; i++)
    		if(dis[i]>tmp){
    			tmp = dis[i];
    			s1 = i;
    		}
    	dij(s1);
    	tmp = dis[1];
    	for(int i=1; i<=n; i++){
    		if(tmp<dis[i])
    			tmp = dis[i];
    	}
    	ll res = tmp;
    	printf("%lld
    ", res*10+(res+1)*res/2);
    	return 0;
    }
    

    虽然可以使用Dijstra算法来解决这个问题,但是我忽略了一个问题,就是这是一个棵树,树是没有环等等复杂结构的,因此是可以通过深搜加上dp来进行解决。

    参考的这个博客:https://www.cnblogs.com/youdiankun/p/3591722.html

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<string>
    #include<stack>
    #include<queue>
    #include<map>
    #include<set>
    #include<sstream>
    typedef long long ll;
    using namespace std;
    const double eps=1e-6;
    const int inf=0x3f3f3f3f;
    const int MAXN=1E5+7;
    struct node{
    	int to, w, nt;
    }edge[MAXN];
    int head[MAXN], m=1; //边是从1开始的,这样就不用初始化head了 
    inline void addedge(int u, int v, int w){
    	edge[m].to = v;
    	edge[m].w = w;
    	edge[m].nt = head[u];
    	head[u] = m++;
    } 
    int dp[MAXN];
    bool vis[MAXN];
    int n, ans;
    void dfs(int s){
    	int k = head[s];
    	int tmp = 0;
    	while(k>0){
    		int t = edge[k].to;
    		if(!vis[t]){
    			vis[t] = 1;
    			dfs(t);
    			tmp = max(tmp, dp[s]+dp[t]+edge[k].w);
    			dp[s]=max(dp[s], dp[t]+edge[k].w);
    		}
    		k = edge[k].nt;
    	}
    	ans = max(ans, tmp);
    }
    int main()
    {
    	scanf("%d", &n);
    	int u, v, w;
    	for(int i=1; i<n; i++){
    		scanf("%d%d%d", &u, &v, &w);
    		addedge(u, v, w);
    		addedge(v, u, w);
    	}
    	vis[1] = true;
    	dfs(1);
    	ll ret = ans;
    	printf("%lld
    ", ret*(21+ret)/2);
    	return 0;
    }
    
    欢迎评论交流!
  • 相关阅读:
    C# 五子棋_GDI+实现
    SAE python+chrome扩展快速存储喜欢的图片(可做图床)
    C# 生成迷宫及寻路
    解决 yii2 从数据库查出来的数据都变成了字符串格式
    英语词根3
    “诸葛马前课-小六壬”全面解析
    Ubuntu 尝试
    ListView + ToolTip 的問題
    英语词根 1
    英语词根6
  • 原文地址:https://www.cnblogs.com/alking1001/p/14526639.html
Copyright © 2011-2022 走看看