本文网址:https://blog.csdn.net/xiaomaolin2/article/details/103496715

传送门:https://nanti.jisuanke.com/t/42580

首先这是个图论题,但是完全可以不用图论算法做,用简单的分析加上贪心即可 。

题意:N个点、M条带权边,其中有一部分(c == 1)为白边,一部分为(c == 0)为黑边,问在限制选择白边的最大数量为k的前  提下能不能完全连接这N个点,能连接时的最大被选中边权和为多少。

解题思路:黑边全选了,看有多少点没有被连接,然后在能到未连接点的白边中选择最长的。

具体实现,先上代码:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <queue>
#include <cmath>
#include <map>
#include <set>
using namespace std;
typedef long long ll;

const int maxn=5e5+10;
set<int>ss;
int T;
int n,m,k;

struct edge{
	int l;
	int r;
	int len;
	int flag;
}edge[maxn];

int cmp(struct edge a,struct edge b){
	return a.len > b.len;
}

int main(){
	scanf("%d",&T);
	while(T--){
		ll sum = 0;
		ss.clear();
		scanf("%d%d%d",&n,&m,&k);
		int flag[n + 1] = {0};
		int white = 0;
		int l,r,len,flag1;
		for(int i = 0;i < m;i++){
			edge[i].flag = 0;
			scanf("%d%d%d%d",&l,&r,&len,&flag1);
			if(flag1){
				edge[white].l = l;
				edge[white].r = r;
				edge[white++].len = len;
			}
			else{
				flag[l]++;
				flag[r]++;
				sum += len; 
			}
		}
		for(int i = 1;i <= n;i++){
			if(flag[i] < 1) ss.insert(i);
		}
	/*/(*)	for(set<int>::iterator it = ss.begin();it != ss.end();it++){
			printf("%d\n",*it);
		}*/
		sort(edge,edge + white,cmp);
		for(int i = 0;i < white;i++){
			if(ss.find(edge[i].l) != ss.end() || ss.find(edge[i].r) != ss.end()){
				ss.erase(edge[i].l);
				ss.erase(edge[i].r);
				sum += edge[i].len;
				edge[i].flag = 1;
				k--;
				//printf("添加边%d-%d-%d\n",edge[i].l,edge[i].r,edge[i].len);
			}
			if(ss.empty() || !k) break;
		}
		if(ss.empty()) {
			for(int i = 0;i < m;i++){
				if(k <= 0) break;
				if(edge[i].flag == 0){
					sum += edge[i].len;
					edge[i].flag = 1;
					k--;
				}	
			}
			printf("%lld\n",sum);
		}
		else{
			printf("-1\n");
			//printf("%lld\n",sum);
		}
	}
	return 0;
}

 有问题可以联系2339814485(QQ)、17781101461(微信),希望与大家多多交流。