1. 程式人生 > >POJ 1849 Two(遍歷樹)

POJ 1849 Two(遍歷樹)

bold cost spa align div col sizeof 最小 turn

POJ 1849 Two(遍歷樹)

http://poj.org/problem?id=1849

題意:

有一顆n個結點的帶權的無向樹, 在s結點放兩個機器人, 這兩個機器人會把樹的每條邊都走一遍, 可是最後機器人不要求回到出發點. 問你兩個機器人走的路總長之和的最小值是多少?

分析:

首先本題僅僅要求出樹的直徑, 然後用樹的總長sum*2-樹的直徑就是所求結果. 以下一步步來說明為什麽是這種.

1.如果僅僅有1個機器人遍歷樹,且要求回到原點, 它最少須要走多少路?

答: 它須要走樹總長sum的兩倍, 即每條樹邊它都要走兩次才行. 這個結論畫個圖就明確了, 對於每條邊, 機器人要走過該邊, 之後還要從該邊回去(不回來就不能回到出發點了

). 所以自然是sum*2.

2.如果1問中的機器人遍歷樹,可是不要求它回到原點, 那麽它最少須要走多少路?

答: 最少須要走sum-[從出發點能走到最遠的點的距離]. 在行走的過程中每一個分叉, 它走過去,又走回來就可以. 能夠反證得出.

3.如果有兩個機器人從s出發,遍歷整個樹且終於回到出發點. 它們行走的最短距離是?

答: 樹總長的兩倍. 每一個機器人都必須回到原點, 那麽必定每條邊至少要被走兩次.

4.如果有兩個機器人從s出發,遍歷整個樹且它們不須要回到出發點. 它們行走的最短距離是?

答: 樹總長的兩倍-樹的直徑. 機器人出去不回來,則所走路徑中有一條簡單路徑是能夠僅僅走一遍的,派出了兩個點去遍歷,也就是說有兩條簡單路徑是能夠直走一邊的,我們要使這兩條簡單路徑的總和盡可能的長,就轉換為了樹的最長路徑問題了.

註意:上面第4種情況, 兩個機器人從哪點出發都是沒有不論什麽差別的. 由於假設它們出發點不在樹的直徑上, 那麽它們一定能夠一起移動到樹直徑上的某個點上,然後分別朝樹直徑的兩個方向走, 而且遍歷它們走的樹直徑的全部分叉路兩次.

AC代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=100000+5;

//邊結構
struct Edge
{
    Edge(){}
    Edge(int to,int cost,int next):to(to),cost(cost),next(next){}
    int to;
    int cost;
    int next;
}edges[maxn];
int cnt=0;//總邊數
int head[maxn];

//加入兩條有向邊
void AddEdge(int u,int v,int cost)
{
    edges[cnt]=Edge(v,cost,head[u]);
    head[u]=cnt++;
    edges[cnt]=Edge(u,cost,head[v]);
    head[v]=cnt++;
}

int dist[maxn];

//返回從s能到達的最長點編號
int BFS(int s)
{
    int max_dist=0;
    int id=s;
    queue<int> Q;
    memset(dist,-1,sizeof(dist));
    dist[s]=0;
    Q.push(s);

    while(!Q.empty())
    {
        int u=Q.front(); Q.pop();
        if(dist[u]>max_dist)
            max_dist=dist[id=u];

        for(int i=head[u]; i!=-1; i=edges[i].next)
        {
            Edge &e=edges[i];
            if(dist[e.to]==-1)
            {
                dist[e.to]=dist[u]+e.cost;
                Q.push(e.to);
            }
        }
    }
    return id;
}


int main()
{
    int n,s;
    while(scanf("%d%d",&n,&s)==2)
    {
        int sum=0;//樹的總長
        memset(head,-1,sizeof(head));
        cnt=0;
        for(int i=1;i<=n-1;i++)
        {
            int u,v,cost;
            scanf("%d%d%d",&u,&v,&cost);
            sum+=cost;
            AddEdge(u,v,cost);
        }

        printf("%d\n",sum*2-dist[BFS(BFS(s))]);
    }
    return 0;
}

POJ 1849 Two(遍歷樹)