不清楚并查集可以戳这
#include
#define maxn 200005
using namespace std;
struct node{
int u;
int v;
int w;
}edge[maxn];
bool cmp(node a, node b){//按边权值排序
return a.w < b.w;
}
int sum, n, m, ans;
int dad[maxn];
void init(){//初始化
for(int i = 1 ; i <= n ; ++ i){
dad[i] = i;
}
}
int find_dad(int i){//递归状压找祖宗
if(dad[i] == i)
return i;
else
return dad[i] = find_dad(dad[i]);
}
int hebin(int x, int y){//合并
int zx = find_dad(x);
int zy = find_dad(y);
if(zx != zy){
dad[zy] = zx;
return 1;
}
return 0;
}
int main()
{
scanf("%d %d", &n, &m);
init();
for(int i = 1 ; i <= m ; ++ i){
scanf("%d %d %d", &edge[i].u, &edge[i].v, &edge[i].w);
}
sort(edge + 1, edge + 1 + m, cmp);
for(int i = 1 ; i <= m ; ++ i){
if(hebin(edge[i].u, edge[i].v)){//如果不在一个集合,合并
sum ++;
ans += edge[i].w;
}
if(sum == n - 1) break;//选出n-1条边退出
}
cout<<ans;
return 0;
}
想了解链式前向星的戳这里
#include
#define INF 0x3f3f3f3f
#define maxn 200005
#define maxm 5005
using namespace std;
struct node{
int to;
int quan;
int next;
}edge[maxn << 1];//双向边开两倍
int n, m, sum, ans, cnt;
int head[maxm], book[maxm], dis[maxm];
void add(int u, int v, int w){//链式前向星存图
edge[cnt].to = v;
edge[cnt].quan = w;
edge[cnt].next = head[u];
head[u] = cnt ++;
}
int main()
{
int u, v, w;
memset(head, -1, sizeof(head));
scanf("%d %d", &n, &m);
for(int i = 1 ; i <= n ; ++ i) dis[i] = INF;
for(int i = 1 ; i <= m ; ++ i){
scanf("%d %d %d", &u, &v, &w);
add(u, v, w); add(v, u, w);//双向加边
}
for(int i = head[1] ; i != -1 ; i = edge[i].next){
int tt = edge[i].to;
dis[tt] = min(dis[tt], edge[i].quan);
}
book[1] = 1;
sum ++;
while(sum < n){
int mini = INF, t = -1;
for(int i = 1 ; i <= n ; ++ i){
if(dis[i] < mini && !book[i]){
mini = dis[i];
t = i;
}
}
book[t] = 1;
sum ++; ans += dis[t];
for(int i = head[t] ; i != -1 ; i = edge[i].next){
int tt = edge[i].to;
if(dis[tt] > edge[i].quan && !book[tt]){
dis[tt] = edge[i].quan;
}
}
}
cout<<ans;
return 0;
}
用时: 196ms / 内存: 5420KB
#include
#define INF 0x3f3f3f3f
#define maxn 200005
#define maxm 5005
using namespace std;
struct node{
int to;
int quan;
int next;
}edge[maxn << 1];
int n, m, sum, ans, cnt;
int head[maxm], book[maxm], dis[maxm];
int h[maxm], pos[maxm], siz;
void add(int u, int v, int w){
edge[cnt].to = v;
edge[cnt].quan = w;
edge[cnt].next = head[u];
head[u] = cnt ++;
}
void init(){
siz = n;
for(int i = 1 ; i <= siz ; ++ i){
pos[i] = i; h[i] = i;
}
}
void siftdown(int i){//传入一个需要向下调整的节点编号i,即从编号为i的点向下调整
int flag = 0, t;//flag代表是否还需要向下调整
while(i * 2 <= siz && !flag){//只要i节点有左儿子,并且需要继续向下调整就执行
if(dis[h[i]] > dis[h[i * 2]])//判断与左儿子大小,t记录较小节点编号
t = i * 2;
else
t = i;
if(i * 2 + 1 <= siz){//如果它还有右儿子,就继续比较,也记录小的节点的编号
if(dis[h[i * 2 + 1]] < dis[h[t]])
t = i * 2 + 1;
}
if(t != i){//如果最小节点编号不是自己,说明子节点有比自己还小的
swap(h[t], h[i]);
swap(pos[h[t]], pos[h[i]]);
i = t;//更新i为与它交换节点的编号。
}
else flag = 1;//否则说明当前节点已经比他的子节点小,无需调整
}
}
void siftup(int i){//传入一个需要向上调整的节点编号
int flag = 0;//flag代表是否还需要向上调整
if(i == 1) return;//如果是堆顶,就返回,无需调整
while(i != 1 && !flag){//不是堆顶并且i节点的值比父节点小就向上调整
if(dis[h[i]] < dis[h[i / 2]]){//判断是否小于父节点
swap(h[i], h[i / 2]);//交换
swap(pos[h[i]], pos[h[i / 2]]);
}
else flag = 1;//当前节点比父节点大了就无需调整
i /= 2;//更新i的编号
}
}
void heap(){//建立小根堆
for(int i = siz / 2 ; i >= 1 ; i --){
siftdown(i);
}
}
int pop(){
int t;
t = h[1];
pos[t] = 0;
h[1] = h[siz];
pos[h[1]] = 1;
siz --;
siftdown(1);
return t;
}
void prime()
{
book[1] = 1;
sum ++;
while(sum < n){
int mini = INF, t = -1;
t = pop();
book[t] = 1;
sum ++; ans += dis[t];
for(int i = head[t] ; i != -1 ; i = edge[i].next){
int tt = edge[i].to;
if(dis[tt] > edge[i].quan && !book[tt]){
dis[tt] = edge[i].quan;
siftup(pos[tt]);
}
}
}
}
int main()
{
int u, v, w;
memset(head, -1, sizeof(head));
scanf("%d %d", &n, &m);
for(int i = 1 ; i <= n ; ++ i) dis[i] = INF;
for(int i = 1 ; i <= m ; ++ i){
scanf("%d %d %d", &u, &v, &w);
add(u, v, w); add(v, u, w);
}
for(int i = head[1] ; i != -1 ; i = edge[i].next){
int tt = edge[i].to;
dis[tt] = min(dis[tt], edge[i].quan);
}
init();
heap();
prime();
cout<<ans;
return 0;
}