這好像很裸的樣子,題目說了一堆廢話,最後其實就是讓求三個點,使得\(AB+BC\)最小,感性的理解蒙一下,應該有一條邊是直徑,否則把任意一條邊換成直徑均可以使答案更優,而後就找直徑唄,找完直徑枚舉直徑兩端點到其餘點的距離,最後答案爲直徑長+\(max(min(dis1,dis2))\),好像就水過這道題了?
因爲它是個樹,因此根據某學長的理論,隨便跑均可以,我dfs忘記咋寫的了,想練一下spfa來,畢竟我那個不熟,但看了看時間太晚了就打了一個dij,沒想到真的過了。。。證實的話明天心情好再補吧ios
#include<iostream> #include<queue> #define ll long long using namespace std; const int N=2e5+10; struct Edge{ int to,nxt; ll val; }e[N<<1]; struct Node{ int id;ll val; Node(){} Node(int a,ll b){id=a,val=b;} bool operator <(const Node&A)const { return val>A.val; } }; int Head[N],len; void Ins(int a,int b,ll c){ e[++len].to=b;e[len].val=c; e[len].nxt=Head[a];Head[a]=len; } int n;bool inq[N]; ll dis1[N],dis2[N]; int dij(int s,ll dis[N]){ for(int i=1;i<=n;i++){ dis[i]=1e17; inq[i]=0; } dis[s]=0;inq[s]=1; priority_queue<Node> q;q.push(Node(s,0)); while(!q.empty()){ Node u=q.top();q.pop();inq[u.id]=0; for(int i=Head[u.id];i;i=e[i].nxt){ int v=e[i].to; if(inq[v])continue; inq[v]=1; if(dis[v]>dis[u.id]+e[i].val){ dis[v]=dis[u.id]+e[i].val; q.push(Node(v,dis[v])); } } } ll Max=0;int id=0; for(int i=1;i<=n;i++) if(dis[i]>Max)Max=dis[i],id=i; return id; } int main(){ ios::sync_with_stdio(false); int m; cin>>n>>m; for(int i=1;i<=m;i++){ int a,b;ll c; cin>>a>>b>>c; Ins(a,b,c);Ins(b,a,c); } int a=dij(1,dis1); int b=dij(a,dis2); dij(b,dis1); ll Max=0; for(int i=1;i<=n;i++) Max=max(Max,min(dis1[i],dis2[i])); cout<<dis2[b]+Max; }
你會發現我在函數裏寫的是手動賦值,爲啥不\(memset\)呢,這裏用\(memset\)的話會出問題,又可能要問了,以前跑最短路用沒出過問題啊,但這裏是不同的,這裏是對傳進來的一個數組進行復制,\(memset\)自己沒有問題,問題出在\(size of\)上,\(size of\)的處理時間的在編譯期,也就是說對於動態生成的數組大小是不能用\(sizeof\)來算出來的。由於若是傳到函數裏,數組會退化成指針,因而\(size of\)就返回了指針的大小,這顯然不是咱們想要的,解決問題的辦法有兩個。一是像我那樣,二是由於每次傳的\(dis\)數組大小同樣,直接寫\(size of dis1\),這樣編譯器就能夠肯定咱們\(size of\)的大小了。數組