作者:王政凱、王培軒、林子鈞
頂點
邊
有時候會有點權
或是邊權
3
9
4
1
7
3
3
8
2
6
1
9
7
4
點的度數:該點連接的邊數
4
2
2
2
1
1
0
多個相鄰點及其連邊的集合
起點終點相同的路徑
3
9
4
1
7
3
3
8
2
6
1
9
7
4
3
9
4
1
7
3
3
8
2
6
1
9
7
4
沒有重邊或自環
所有點之間皆有連邊
沒有環的圖稱為森林,每個聯通分量為一樹
樹
將點分割為兩個互斥集,且集合內無相鄰點
二維陣列存圖
n個點:G[n][n]
G[i][j]:從i點連到j點的邊權
2
5
3
1
4
3
8
2
6
7
vector陣列存圖
n個點:vector G[n]
2
5
3
1
4
3
8
2
6
7
1 : {2,3}
2 : {1,3},{2,7},{3,2},{5,8}
3 : {2,2},{4,6}
4 : {3,6}
5 : {2,8}
走到一個點
把所有相鄰點丟進stack
取stack中top繼續走下去
走到一個點
把所有相鄰點丟進queue後端
取queue前端繼續走下去
有\(n\)個元素,各自屬於某個集合(集合間互斥
希望支援以下兩個操作
每個人會有上級,一開始大家的上級都是自己
一個集合裡面的頭頭以自己為上級
查詢時不斷跳到上級直到頭頭
合併時將一個集合的頭頭變成另一個集合頭頭的上級
<我是頭頭
路徑壓縮:找到頭頭後直接把自已的上級設為頭頭
啟發式合併:合併兩集合時將小的和到大的
都使用的複雜度:\(O(\alpha(n)) \)(很快
int dsu[MAXN];
int find(int pos){
if(dsu[pos]!=pos){
dsu[pos]=find(dsu[pos]);
return dsu[pos];
}else return pos;
}
void unnion(int a,int b){
dsu[find(a)]=find(b);
}
int main(){
for(int i=1;i<MAXN;i++)dsu[i]=i;
}
裸的DSU
想一下的DSU
無向連通圖中的子圖
滿足點集和原圖相同
且是一個樹
所有生成樹中邊權和最小的生成樹
性質:合併兩最小生成樹時
以最小的邊的合併最好
每次找最小的邊
利用DSU看他們是不是在同一個連通塊
不同就合併
\(O(Elog(V))\)
#define mp make_pair
int dsu[MAXN];
int find(int pos){
if(dsu[pos]!=pos){
dsu[pos]=find(dsu[pos]);
return dsu[pos];
}else return pos;
}
void unnion(int a,int b){
dsu[find(a)]=find(b);
}
int main(){
for(int i=1;i<MAXN;i++)dsu[i]=i;
}
int main(){
priority_queue<pair<int,pair<int,int>>,
vector<pair<int,pair<int,int>>>,greater<pair<int,pair<int,int>>>> qq;
int n,m;cin>>n>>m;
while(m--){
int a,b,c;cin>>a>>b>>c;
qq.push(mp(c,mp(a,b)));
}
int ans=0;
whlie(qq.size()){
auto top=qq.top();
if(find(top.S.S)!=find(top.S.F)){
unnion(top.S.F,top.S.S);
ans+=top.F;
}
}
cout<<ans<<endl;
}
選任一個當起點
每次將離當前最小生成樹最近的點
加入最小生成樹
稀疏圖\(O(Elog(V))\)
稠密圖\(O(V^2)\)
struct qq{
ll a,b,c;
};
bitset<5001> bi;
ll ve[5001];
qq arr[5001];
ll cost=0;
int main(){
int n,cnt=0;
cin>>n;
for(int i=0;i<n;i++){
struct qq qq;
cin>>qq.a>>qq.b>>qq.c;
arr[i]=qq;
}
for(int i=0;i<5001;i++)ve[i]=100000000000;
int tmp=0;
while(cnt<n){
ve[tmp]=0;
for(int i=0;i<n;i++){
ve[i]=min(ve[i],(arr[i].a-arr[tmp].a)*(arr[i].a-arr[tmp].a)+(arr[i].b-arr[tmp].b)*(arr[i].b-arr[tmp].b)+(arr[i].c-arr[tmp].c)*(arr[i].c-arr[tmp].c));
}
ll min=100000000000,ind;
for(int i=0;i<n;i++){
if(ve[i]<min&&ve[i]!=0){
ind=i;
min=ve[i];
}
}
cost+=ve[ind];
tmp=ind;
cnt++;
}
cout<<cost<<endl;
return 0;
}