CSU1633-Landline Telephone Network-最小生成树

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

目录

题意:传送门

 原题目描述在最下面。
 n个点,m条边,k个坏点。求一最小生成树,满足任意两点的路径间没有一个坏点。

思路:

 显然坏点只能当叶子。
 我选择kurskal算法,第一次枚举不取有坏点作为端点的边,第二次枚举只有一个端点是坏点的边。

AC代码:

#include<bits/stdc++.h>
#define mme(a,b) memset((a),(b),sizeof((a)))
#define fuck(x) cout<<"* "<<x<<"\n"
#define all(x) (x).begin(),(x).end()
#define iis std::ios::sync_with_stdio(false)
using namespace std;
typedef long long LL;
const int N = 1e3+5;
const int M = 1e5+5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int n, m, k;
int fa[N];
struct lp{
  int u,v,w;
}cw[M];
int vis[N],cnt[N];
bool cmp(const lp &a,const lp &b){
  return a.w<b.w;
}
int Fi(int x){
  return fa[x]==x?x:fa[x]=Fi(fa[x]);
}
int main(){
  while(~scanf("%d%d%d", &n,&m,&k)){
    for(int i=1;i<=n;++i)vis[i]=cnt[i]=0;
    for(int i=1;i<=n;++i)fa[i]=i;
    for(int i=0,x;i<k;++i){
      scanf("%d",&x);
      vis[x]=1;
    }
    for(int i=0,u,v,w;i<m;++i){
      scanf("%d%d%d",&u,&v,&w);
      cw[i].u=u;cw[i].v=v;cw[i].w=w;
    }
    if(n==2){
      printf("%d\n", cw[0].w);
      continue;
    }
    sort(cw,cw+m,cmp);
    int ans=0,num=0;
    for(int i=0;i<m;++i){
      if(vis[cw[i].u]||vis[cw[i].v])continue;
      int pa = Fi(cw[i].u),pb=Fi(cw[i].v);
      if(pa==pb)continue;
      num++;
      ans+=cw[i].w;
      fa[pb]=pa;
    }
    for(int i=0;i<m;++i){
      if(vis[cw[i].u]^vis[cw[i].v]){
        if(vis[cw[i].u]&&cnt[cw[i].u])continue;
        cnt[cw[i].u]=1;
        if(vis[cw[i].v]&&cnt[cw[i].v])continue;
        cnt[cw[i].v]=1;
        int pa=Fi(cw[i].u),pb=Fi(cw[i].v);
        if(pa==pb)continue;
        num++;
        ans+=cw[i].w;
        fa[pb]=pa;
        if(num==n-1)break;
      }
    }
    if(num!=n-1){
      printf("impossible\n");
      continue;
    }
    printf("%d\n", ans);
  }
  return 0;
}


原题目描述:

这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_39599067/article/details/81326319
今日推荐