POJ1849

7 篇文章 2 订阅

POJ1849

题意:

​ 有一颗n个结点的带权的无向树, 在s结点放两个机器人, 这两个机器人会把树的每条边都走一遍, 但是最后机器人不要求回到出发点. 问你两个机器人走的路总长之和的最小值是多少?

思路:

1. 假设只有1个机器人遍历树,且要求回到原点, 它最少需要走多少路?

​ 答: 它需要走树总长sum的两倍, 即每条树边它都要走两次才行. 这个结论画个图就明白了, 对于每条边, 机器人要走过该边, 之后还要从该边回去(不回来就不能回到出发点了). 所以自然是sum*2.

2.假设1问中的机器人遍历树,但是不要求它回到原点, 那么它最少需要走多少路?

​ 答: 最少需要走sum-[从出发点能走到最远的点的距离]. 在行走的过程中每个分叉, 它走过去,又走回来即可. 可以反证得出.

3.假设有两个机器人从s出发,遍历整个树且最终回到出发点. 它们行走的最短距离是?

​ 答: 树总长的两倍. 每个机器人都必须回到原点, 那么必然每条边至少要被走两次.

4.假设有两个机器人从s出发,遍历整个树且它们不需要回到出发点. 它们行走的最短距离是?

​ 答: 树总长的两倍-树的直径. 机器人出去不回来,则所走路径中有一条简单路径是可以只走一遍的,派出了两个点去遍历,也就是说有两条简单路径是可以直走一边的,我们要使这两条简单路径的总和尽可能的长,就转换为了树的最长路径问题了.

​ 注意:上面第4种情况, 两个机器人从哪点出发都是没有任何区别的. 因为如果它们出发点不在树的直径上, 那么它们一定可以一起移动到树直径上的某个点上,然后分别朝树直径的两个方向走, 并且遍历它们走的树直径的所有分叉路两次.

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

const int maxn = 100000+10;

struct Edge
{
    int e,v;
    int next;
}edge[maxn*2];

int n,s;
int head[maxn],pos;
int dis[maxn];

void init()
{
    pos = 0;
    memset(head,-1,sizeof(head));
}

void add_edge(int a,int b,int c)
{
    edge[pos].e = b;
    edge[pos].v = c;
    edge[pos].next = head[a];
    head[a] = pos++;
    edge[pos].e = a;
    edge[pos].v = c;
    edge[pos].next = head[b];
    head[b] = pos++;
}

int bfs(int s)
{
    memset(dis,-1,sizeof(dis));
    queue<int>q;
    q.push(s);
    dis[s] = 0;
    int Max = 0,id;
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        if(dis[u] > Max) Max = dis[id = u];
        for(int i = head[u];i != -1; i = edge[i].next) {
            int to = edge[i].e;
            if(dis[to] == -1 ){
                dis[to] = dis[u] + edge[i].v;
                q.push(to);
            }
        }
    }
    return id;
}

int main()
{
    //freopen("in.txt","r",stdin);

    while(scanf("%d%d",&n,&s) != EOF) {
        init();
        int ans = 0;
        for(int i = 1;i < n; i++) {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            add_edge(a,b,c);
            ans += c;
        }
        int start = bfs(1);
        int ansid = bfs(start);
        printf("%d\n",ans*2-dis[ansid]);
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值