1. 程式人生 > >Avito Cool Challenge 2018:D. Maximum Distance (最小生成樹)

Avito Cool Challenge 2018:D. Maximum Distance (最小生成樹)

題目連結

題意 :

給出一個聯通圖和一些特殊的點,現在定義cost(u,v)為一條從u到v的路徑上面邊權的最大值 , 

定義dis(u,v) 為從u到v 路徑上面cost 的最小值

然後求所有特殊點到其他特殊點的最大距離

 

題解:

做這題前,首先思考一件事情,對於一顆樹來說點到點的距離是不是就是樹上面路徑的邊權最大值

我們來證明一下:假設在最小生成樹上面的路徑cost為w1,另外在原圖中還有一條路徑從u到v,其cost為w2,那麼必然有w2>w1的。那麼我們最後的dis一定是w1。

那麼我們現在的目標就是求特殊點到特殊點之間的最大距離。注意一下這裡是從一個特殊點到其它所有特殊點的最大距離

我們根據Kruskal 演算法的構建過程 , 在構建樹的時候是先構造小的邊的 , 所以我們就可以在Kruskal加邊的時候更新答案 , 

我們假設現在有兩個集合,現在將其連線起來,當滿足兩個集合裡面都有特殊點時我們就可以更新答案了,否則就不行。

轉載 現在還有一些問題沒有解決 , 待後跟新

#include<bits/stdc++.h>
using namespace std;

const int maxn = 100001;//最大點數
int c[maxn], N,M,k;//並查集使用
int cnt;
bool a[maxn];
int VAL[maxn];
struct EDGE{ int from, to, w; bool operator < (const EDGE &rhs) const{ return this->w < rhs.w; }; }Edge[maxn];//儲存邊的資訊,包括起點/終點/權值 inline void init() { for(int i=0; i<=N; i++) c[i] = i; cnt = 0; } inline void AddEdge(int from, int to, int weight) { Edge[cnt].
from = from; Edge[cnt].to = to; Edge[cnt].w = weight; cnt++; } int Findset(int x) { int root = x; while(c[root] != root) root = c[root]; int idx; while(c[x] != root){ /// 路徑壓縮 idx = c[x]; c[x] = root; x = idx; } return root; } int Kruskal()//傳入點數,返回最小生成樹的權值,如果不連通返回-1 { sort(Edge,Edge+cnt); int EdgeCnt=0;//計算加入的邊數 int Cost=0; int MAX=0; for(int i=0;i<cnt;i++){ int u=Edge[i].from; int v=Edge[i].to; int w=Edge[i].w; int R1 = Findset(u); int R2 = Findset(v); if(R1==R2) continue; c[R1]=R2; if(a[u]) VAL[R1]++;//標記的點 if(a[v]) VAL[R2]++; if(VAL[R1] && VAL[R2] )//如果標記的點都有 MAX=w; VAL[R2]+=VAL[R1]; EdgeCnt++; if(EdgeCnt==N-1) break; } if(EdgeCnt<N-1) return -1;//不連通 else return MAX; } int main() { scanf("%d%d%d",&N,&M,&k); init(); int Val; for(int i=1 ; i<=k ; i++) { scanf("%d",&Val); a[Val]=1; } for(int i=1 ; i<=M ; i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); AddEdge(u,v,w); } int P=Kruskal(); for(int i=1 ; i<=k ; i++) printf("%d ",P); // printf("%d\n", Kruskal()); return 0; }
View Code