題面
Description
N個點,M條邊,其中K條邊必選,求所有點點之間都有可達的最小代價。數據保證有解。
Input
第一行兩個整數n,m。
第二行到m+1行,每行四個非負整數,p,u,v,w 當p=1時,表示必選邊;當p=2時,表示可選邊;u,v,w一條無向邊端點爲u和v,權值爲w。
Output
最小費用。
Sample Input
5 6
1 1 2 1
1 2 3 1
1 3 4 1
1 4 1 1
2 2 5 10
2 2 5 5
Sample Output
9
HINT
數據範圍:
對於30%的數據,n<=10 m<=100
對於50%的數據, n<=200 m<=1000
對於100%的數據,n<=2000 m<=10000
題目分析
題目的意思是很好理解的,無非是在取了特定邊的情況下,求最小連通圖——最小生成樹
實現方面便是,先將特定的邊加到圖中並且對邊進行處理,之後把剩餘的再整理一下,去算最小生成樹
代碼
#include <bits/stdc++.h>
using namespace std;
struct node
{
int u;
int v;
int w;
}e[500009];
long long f[500009];
long long n,m;
long long ans,cnt = 0;
bool cmp(node x,node y)
{
return x.w < y.w;
}
int find(int x) //尋根
{
if (f[x] == x) return x;
f[x] = find(f[x]);
return f[x];
}
long long kruskal()
{
long long sum = 0;
for (int i = 1; i <= cnt; i++)
if (find(e[i].u) != find(e[i].v)) //對環的判斷
f[find(e[i].v)] = find(e[i].u),
sum += e[i].w;
return sum;
}
int main()
{
long long p,u1,v1,w1;
cin>>n>>m;
for (int i = 1; i <= n; i++) f[i] = i;
for (int i = 1; i <= m; i++)
{
scanf("%d%d%d%d",&p,&u1,&v1,&w1);
if (p == 1) //必選的邊,加進來,指向同一個父節點
f[find(v1)] = find(u1),
ans += w1;
if (p == 2) //非必選邊,加進來,不一定處理
cnt++,
e[cnt].u = u1,
e[cnt].v = v1,
e[cnt].w = w1;
}
sort(e+1,e+cnt+1,cmp); //給點排序
ans += kruskal(); //跑kruskal
cout<<ans;
return 0;
}