【次小生成树】PAT (Top Level) 1016 Uniqueness of MST (35)

该博客主要讨论PAT (Top Level) 1016题目的解决方案,涉及次小生成树的概念。文章指出,如果最小生成树唯一,输出其权值和并显示'Yes';若不唯一,则同样输出权值和但显示'No';若图不连通,则输出'No MST'和连通块数量。作者提醒在次小生成树的代码实现中注意i与j的区别,并确保试探标记的正确处理。

Think:
1知识点:次小生成树
2题意:
(1):若最小生成树存在且唯一,第一行输出最小生成树权值和,第二行输出Yes
(2):若最小生成树存在且不唯一,第一行输出最小生成树权值和,第二行输出No
(3):若最小生成树不存在即图不连通,第一行输出”No MST”,第二行输出连通块数量
3反思:
(1):次小生成树代码实现部分i与j不要混淆
(2):次小生成树代码实现部分试探标记不要忘记当前边试探完成之后及时取消

PAT题集-题目链接

以下为Accepted代码

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

struct Edge{
  int u, v, w;
  int flag;
  bool operator < (const Edge &b) const{
    return w < b.w;
  }
}edge[404014];

int f[504];
int tp, link[404014];

void init_f(int n);
int get_f(int x);
bool Merge(int x, int y);

int main(){
  int n, m, num, sum;
  while(~scanf("%d %d", &n, &m)){
    for(int i = 0; i < m; i++){
      scanf("%d %d %d", &edge[i].u, &edge[i].v, &edge[i].w);
      edge[i].flag = 0;
    }
    sort(edge, edge+m);/*按边权升序排序*/
    init_f(n);/*Kruskal算法并查集标记数组初始化初始化*/
    tp = 0, num = 0, sum = 0;/*路径记录变量以及Kruskal算法记录变量初始化*/
    for(int i = 0; i < m; i++){
      if(Merge(edge[i].u, edge[i].v)){
        num++;
        sum += edge[i].w;
        link[tp++] = i;
        if(num == n-1) break;
      }
    }
    if(num != n-1){
      int cnt = 0;
      for(int i = 1; i <= n; i++){
        if(f[i] == i) cnt++;/*查询图内有几个连通块*/
      }
      printf("No MST\n");
      printf("%d\n", cnt);/*输出图内连通块的数量*/
    }
    else {
      printf("%d\n", sum);
      int i, id, cnt, tmp;
      for(i = 0; i < tp; i++){
        id = link[i];
        edge[id].flag = 1;/*标记试探边*/

        /*Kruskal算法*/
        init_f(n);
        cnt = 0, tmp = 0;
        for(int j = 0; j < m; j++){
          if(edge[j].flag == 0){/*判断当前边是否为试探边*/
            if(Merge(edge[j].u, edge[j].v)){/*尝试下标为j的边是否可以加入当前的生成树*/
              cnt++;
              tmp += edge[j].w;/*反思:j不要与i混淆写错*/
              if(cnt == n-1) break;
            }
          }
        }

        edge[id].flag = 0;/*试探边试探完成之后取消试探标记*/

        if(cnt == n-1 && tmp == sum) break;/*判断最小生成树是否唯一*/
      }
      if(i < tp) printf("No\n");/*提前终止代表最小生成树不唯一*/
      else printf("Yes\n");
    }
  }
  return 0;
}
void init_f(int n){
  for(int i = 0; i <= n; i++){
    f[i] = i;
  }
  return;
}
int get_f(int x){
  if(x == f[x]) return x;
  return f[x] = get_f(f[x]);
}
bool Merge(int x, int y){
  int t1 = get_f(x);
  int t2 = get_f(y);
  if(t1 != t2){
    f[t2] = t1;
    return true;
  }
  return false;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值