[ICPC2019 南昌站] Bob's Problem

題目描述:

有N個點,M條邊
邊有權值和顏色(黑色 白色)
最多選K條白邊,黑色邊數量不限,問在保證選出的邊讓圖聯通的情況下,邊取值和最大

題目分析:

由於黑色邊沒有限制數量
我們可以先把所有的黑色邊扔進去,做克魯斯卡爾
然後把白邊按照權值降序排列
第一次我們先儘量保證圖聯通,因此當邊鏈接的點不在一個連通塊的時候取這條邊。記錄當前用白邊的數量
然後判斷能否用少於等於K讓圖聯通
如果白邊還有剩餘,我們就儘量把沒用過的白邊權值大的加進去

題目鏈接:

計蒜客

AC代碼:

#include <iostream>
#include <cstdio>
#include <algorithm>
#define int long long
const int maxn=5e4+100;
const int maxm=5e5+100;
struct node{
	int w,u,v;
};
int fa[maxm],used[maxm];
node edge1[maxm],edge2[maxm];
int n,m,k;
int cnt1,cnt2;
inline bool comp(node x,node y){return x.w>y.w;}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline void work()
{
	scanf("%lld%lld%lld",&n,&m,&k);
	cnt1=cnt2=0;
	for(int i=1;i<=n;i++) fa[i]=i,used[i]=0;
	int tot=n;
	for(int i=1;i<=m;i++)
	{
		int u,v,w,c;
		scanf("%lld%lld%lld%lld",&u,&v,&w,&c);
		if(c==0) edge1[++cnt1]=(node){w,u,v};
		else edge2[++cnt2]=(node){w,u,v};
	}
	int ans=0;
	for(int i=1;i<=cnt1;i++)
	{
		int fa1=find(edge1[i].u),fa2=find(edge1[i].v);
		ans+=edge1[i].w;
		if(fa1!=fa2)
		{
			fa[fa1]=fa2;
			tot--;
		}
	}
	std::sort(edge2+1,edge2+cnt2+1,comp);
	int now=0;
	for(int i=1;i<=cnt2&&now!=k;i++)
	{
		if(tot==1) break;
		int fa1=find(edge2[i].u),fa2=find(edge2[i].v);
		if(fa1!=fa2)
		{
			now++;
			used[i]=1;
			fa[fa1]=fa2;
			tot--;
			ans+=edge2[i].w;
		}
	}
	if(tot!=1)
	{
		printf("-1\n");
		return;
	}
	for(int i=1;i<=cnt2&&now!=k;i++)
	if(!used[i])
	{
		now++;
		ans+=edge2[i].w;
	}
	printf("%lld\n",ans);
}
signed main()
{
	int t;
	scanf("%lld",&t);
	while(t--) work();
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章