【CSUST 2036】: 傲娇的点 最小生成树 + 思维

传送门

题意

在这里插入图片描述

分析

关于我去别人oj刷题顺便加强了一波数据这件事
分析一下,傲娇点只能链接一条边,说明他只能和一个连通块构造起来联系
首先我们把没有涉及到傲娇点的所有边构成最小生成树,然后如果构成了一个连通块,我们可以把每一个傲娇点插到连通块上,如果构成了多个连通块,那么必然无法构造出最小生成树

最后需要注意的是,需要特判 n = = 2 n == 2 n==2的情况,这个情况数据应该是没有给出来的,可以测一下

2 1 2
1 2
1 2 3

这组数据,应该是可以构造出来的

代码

#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
#define _CRT_SECURE_NO_WARNINGS
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef vector<int> VI;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 10,M = 1e5 + 10;
const ll mod = 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
int gcd(int a, int b) {return (b > 0) ? gcd(b, a % b) : a;}
bool st[N],num[N];
int q[N];
int n,m,p;

struct edge{
    int x,y,z;
}e[M];

bool cmp(edge a,edge b){
    return a.z < b.z;
}
int find(int x){
    if(x != q[x]) q[x] = find(q[x]);
    return q[x];
}

int Kruskal(){
    sort(e,e + m,cmp);
    for(int i = 1;i <= n;i++) q[i] = i;
    int ans = 0;
    for(int i = 0;i < m;i++){
    	if(st[e[i].x] || st[e[i].y]) continue;
        int a = find(e[i].x),b = find(e[i].y);
        if(a != b){
            ans += e[i].z;
            q[a] = b;
        }
    }    
    return ans;
}



int main() {
	scanf("%d%d%d",&n,&m,&p);
	int l = p;
	for(int i = 1;i <= p;i++){
		int x;
		scanf("%d",&x);
		st[x] = true;
	}
	for(int i = 0;i < m;i++) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
	if(n == 2){
		sort(e,e + m,cmp);
		int ans = -1;
		for(int i = 0;i < m;i++) if(e[i].x != e[i].y) ans = e[i].z;
		di(ans);
		return 0;
	}
	int ans = Kruskal();
	int res = 0;
	p = -1;
	for(int i = 1;i <= n;i++){
		if(st[i]) continue;
		if(i == find(i)) res++,p = i;
	}
	if(res != 1) {
		puts("-1");
		return 0;
	}
	for(int i = 0;i < m;i++){
		int x = e[i].x,y = e[i].y,z = e[i].z;
		int a = find(e[i].x),b = find(e[i].y);
		if(st[x] && st[y]) continue;
		if(st[x] + st[y] == 0) continue;
		if(st[x]){
			if(num[x]) continue;
			ans += z;
			q[a] = b;
			num[x] = true;
		}
		else{
			if(num[y]) continue;
			ans += z;
			q[a] = b;
			num[y] = true;
		}
	}
	res = 0;
	for(int i = 1;i <= n;i++) if(i == find(i)) res++;
	if(res != 1) ans = -1;
	di(ans);
	return 0;
}

/**
*  ┏┓   ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃       ┃
* ┃   ━   ┃ ++ + + +
*  ████━████+
*  ◥██◤ ◥██◤ +
* ┃   ┻   ┃
* ┃       ┃ + +
* ┗━┓   ┏━┛
*   ┃   ┃ + + + +Code is far away from  
*   ┃   ┃ + bug with the animal protecting
*   ┃    ┗━━━┓ 神兽保佑,代码无bug 
*   ┃        ┣┓
*    ┃        ┏┛
*     ┗┓┓┏━┳┓┏┛ + + + +
*    ┃┫┫ ┃┫┫
*    ┗┻┛ ┗┻┛+ + + +
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值