CSU P2326 path 最短路+樹的直徑

CSU P2326 path 最短路+樹的直徑

題解:

通過畫圖觀察,以及貪心考慮得出一個結論,從一個點出發,如果要回到原來的點,則所有邊都要訪問兩次;而在這 道題中訪問到最後一個點則立即停下來,那麼最短路程和就是最後走到離這個點最遠的那個點停下,即所有邊的長度 * 2-這個點走到離它最遠點的距離。
而由於有多個出發點,那是我們利用從樹的直徑的性質,也就是在一棵樹上的一個點的最遠點一定是某一條樹的直徑 的端點,於是我們只需求出某一條樹的直徑,那麼這條直徑的2個端點一定有一個是每個點的最遠點。
我們先隨便選擇一個點,使用最短路徑算法或者dfs,找到某一條直徑的一個端點,再用這個端點再跑一遍最短路徑算法或dfs,找到直徑的另一個端點。然後對於每個可以作爲開始點的點,找到離他們最遠點的距離。取最大值,最 短路程即等於所有路徑長的兩倍減去這個最大值。

代碼如下:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<cmath>
#include<queue>
#include<string>
#include<vector>
#define MAX 100005
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;

int n;//n爲頂點數
int visit[MAX],dis[MAX],flag[MAX],maxdis[MAX];

struct edge{//存儲邊
  int to;//邊的指向
  int cost;//邊的權值
};

vector<edge> adj[MAX];
typedef pair<int,int> p; //first是最短距離,second是頂點的編號

struct cmp{//優先隊列的cmp是一個類
    bool operator()(p a,p b) {
        return a.first>b.first;
    }
};

void dijkstra(int s){
    for(int i=0;i<MAX;i++){
        visit[i]=0;
        dis[i]=INF;
    }
    dis[s]=0;
    priority_queue<p,vector<p>,cmp > q;
    q.push(p(0,s));//將源結點放入優先隊列
    while(!q.empty()){
        p top=q.top();
        q.pop();
        int u=top.second;
        if(visit[u]==0){
            visit[u]=1;
            for(int i=0;i<adj[u].size();i++){
                edge e=adj[u][i];
                if(dis[e.to]>dis[u]+e.cost){
                    dis[e.to]=dis[u]+e.cost;
                    q.push(p(dis[e.to],e.to));
                }
            }
        }
    }
}

int main(){
    scanf("%d",&n);
    int a,b,len,tot=0;
    for(int i=0;i<n-1;i++){
        cin>>a>>b>>len;
        edge e;
        e.to=b;
        e.cost=len;
        adj[a].push_back(e);//adj[a]是從頂點a出發的邊的集合
        e.to=a;
        adj[b].push_back(e);
        tot+=len;
    }
    bool tag=false;
    for(int i=1;i<=n;i++){
        scanf("%d",&flag[i]);
        if(flag[i]) tag=true;
    }
    if(!tag){
        printf("-1");
        return 0;
    }
    dijkstra(1);
    int ends,maxl=-1;
    for(int i=1;i<=n;i++){
        if(dis[i]>maxl){
            maxl=dis[i];
            ends=i;
        }
    }
    dijkstra(ends);
    maxl=-1;
    for(int i=1;i<=n;i++){
        maxdis[i]=dis[i];
        if(dis[i]>maxl){
            maxl=dis[i];
            ends=i;
        }
    }
    dijkstra(ends);
    maxl=-1;
    for(int i=1;i<=n;i++){
        if(dis[i]>maxdis[i]){
            maxdis[i]=dis[i];
        }
        if(flag[i]&&maxdis[i]>maxl){
            maxl=maxdis[i];
        }
    }
    int res=2*tot-maxl;
    printf("%d",res);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章