蓝桥杯——大臣的旅费(树的最大直径)

18 篇文章 0 订阅
8 篇文章 0 订阅
问题描述

很久以前,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的路费。


求树的直径,方法:
树的直径是指树的最长简单路。求法: 两遍BFS :先任选一个起点BFS找到最长路的终点,再从终点进行BFS,则第二次BFS找到的最长路即为树的直径;
              原理: 设起点为u,第一次BFS找到的终点v一定是树的直径的一个端点
              证明: 1) 如果u 是直径上的点,则v显然是直径的终点(因为如果v不是的话,则必定存在另一个点w使得u到w的距离更长,则于BFS找到了v矛盾)
                      2) 如果u不是直径上的点,则u到v必然于树的直径相交(反证),那么交点到v 必然就是直径的后半段了
       
                所以v一定是直径的一个端点,所以从v进行BFS得到的一定是直径长度

bfs:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <stack>
using namespace std;
typedef long long ll;
#define PI 3.1415926535897932
#define E 2.718281828459045
#define INF 0x3f3f3f3f
#define mod 100000007

const int M=1005;
int n,m;
int cnt;
int sx,sy,sz;
//int g[M][M];
int pa[M*10],rankk[M];
int head[M*6],vis[M*100];
int dis[M*100];
ll prime[M*1000];
bool isprime[M*1000];
int lowcost[M],closet[M];
char st1[5050],st2[5050];
int len[M*6];
typedef pair<int ,int> ac;
//vector<int> g[M*10];
int dp[M];
int has[10500];
int month[13]= {0,31,59,90,120,151,181,212,243,273,304,334,0};
int dir[8][2]= {{0,1},{0,-1},{-1,0},{1,0},{1,1},{1,-1},{-1,1},{-1,-1}};

void getpri()
{
    ll i;
    int j;
    cnt=0;
    memset(isprime,false,sizeof(isprime));
    for(i=2; i<1000000LL; i++)
    {
        if(!isprime[i])prime[cnt++]=i;
        for(j=0; j<cnt&&prime[j]*i<1000000LL; j++)
        {
            isprime[i*prime[j]]=1;
            if(i%prime[j]==0)break;
        }
    }
}
struct node
{
    int v,w;
    node(int vv,int ww)
    {
        v=vv;
        w=ww;
    }
};
vector<node> g[M*100];
void bfs(int st)
{
    memset(vis,0,sizeof(vis));
    memset(dis,0,sizeof(dis));
    queue<int>qu;
    //node tmp;
    vis[st]=1;
    cnt=0;
    qu.push(st);
    while(!qu.empty())
    {
        int u=qu.front();
        qu.pop();
        for(int i=0; i<g[u].size(); i++)
        {
            int v=g[u][i].v;
            if(!vis[v]&&dis[v]<dis[u]+g[u][i].w)
            {
                vis[v]=1;
                dis[v]=dis[u]+g[u][i].w;
                qu.push(v);
                if(cnt<dis[v])
                {
                    cnt=dis[v];
                    sx=v;
                }
            }
        }
    }
}
int main()
{
    int i,j,k,t;
    int u,v,w;
    scanf("%d",&n);
    for(i=0; i<n-1; i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        g[u].push_back(node(v,w));
        g[v].push_back(node(u,w));
    }
    sx=1;
    bfs(1);
    bfs(sx);
    printf("%d\n",cnt*10+cnt*(cnt+1)/2);
    return 0;
}

dfs:

struct node
{
    int v,w;
    node(int vv,int ww)
    {
        v=vv;
        w=ww;
    }
};
vector<node> g[M*100];
void dfs(int u,int sum)
{
    if(cnt<sum)
    {
        sx=u;
        cnt=sum;
    }
    vis[u]=1;
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i].v;
        if(!vis[v])
        {
            vis[v]=1;
            dfs(v,sum+g[u][i].w);
        }
    }
}
int main()
{
    int i,j,k,t;
    int u,v,w;
    scanf("%d",&n);
    for(i=0; i<n-1; i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        g[u].push_back(node(v,w));
        g[v].push_back(node(u,w));
    }
    cnt=0;sx=1;
    memset(vis,0,sizeof(vis));
    dfs(1,0);
    memset(vis,0,sizeof(vis));
    dfs(sx,0);
    printf("%d\n",cnt*10+cnt*(cnt+1)/2);
    return 0;
}

扒的spfa实现:http://www.cnblogs.com/icode-girl/p/5281313.html

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <queue>
#define maxn 100010
#define inf 100000000
using  namespace  std;
 
int  n;  // 顶点个数
 
struct  Node {
     int  v;
     int  w;  // 存储该边权值
     int  nxt;
}edge[maxn];
 
int  head[maxn];
int  tot;
 
void  addEdge( int  u,  int  v,  int  w) {
     edge[tot].v = v;
     edge[tot].w = w;
     edge[tot].nxt = head[u];
     head[u] = tot++;
}
 
int  dis[maxn];  // 存储源点到每个顶点的最短距离
int  vis[maxn];  // 判断当前顶点是不是已经入队
 
int  spfa( int  src) {
     for  ( int  i=1; i<=n; ++i) {
         dis[i] = inf;
     }
     dis[src] = 0;
     queue< int > que;
     vis[src] = 1;
     que.push(src);
     while (!que.empty()) {
         int  u = que.front();
         que.pop();
         vis[u] = 0;
         for  ( int  i=head[u]; i!=-1; i=edge[i].nxt) {
             int  v = edge[i].v;
             if  (dis[v] > dis[u] + edge[i].w) {
                 dis[v] = dis[u] + edge[i].w;
                 if  (!vis[v]) {
                     vis[v] = 1;
                     que.push(v);
                 }
             }
         }
     }
}
 
 
int  main() {
 
     memset(head, -1,  sizeof (head));
     tot = 0;
 
     while (cin >> n) {
         for  ( int  i=1; i<n; ++i) {
             int  u, v, w;
             cin >> u >> v >> w;
             addEdge(u, v, w);
             addEdge(v, u, w);
         }
 
         spfa(1);
         int  ans = 0, temp;
         for  ( int  i=1; i<=n; ++i) {
             if  (ans < dis[i]) {
                 ans = dis[i];
                 temp = i;
             }
         }
 
         spfa(temp);
         for  ( int  i=1; i<=n; ++i) {
             if  (ans < dis[i]) {
                 ans = dis[i];
             }
         }
 
         temp = ans;
         ans = (temp*(temp+1))/2;
         ans += 10*temp;
         cout << ans << endl;
     }
     return  0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值