nssl1191,P2700-逐个击破(平津战役)【并查集】

版权声明:原创,未经作者允许禁止转载 https://blog.csdn.net/Mr_wuyongcong/article/details/83188625

正题


题目大意

一棵树n个点
有k个点被占领,删除每一条边都有不同的代价,然后要求所以被占领的点相互隔开,代价最小。


解题思路

我们可以考虑反构图,将边权排序,然后对于每条边,如果加入这条边后不会使敌军连接就加这条边,然后加入,然后用并查集判断敌军是否连接。


code

#include<cstdio>
#include<algorithm>
#define N 100010
using namespace std;
struct node{
	int x,y,w;
}a[N];
int n,k,tot,father[N];
long long ans;
bool army[N];
int find(int x)//找祖先
{
	return father[x]==x?x:father[x]=find(father[x]);
}
bool cmp(node x,node y)
{return x.w>y.w;}
int main()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=k;i++)
	{
	    scanf("%d",&tot);
	    tot++;
	    army[tot]=true;
	}
	for(int i=1;i<n;i++)
	{
		father[i]=i;
		scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
		a[i].x++;a[i].y++;
		ans+=a[i].w;
	}
	father[n]=n;
	sort(a+1,a+n,cmp);
	for(int i=1;i<n;i++)
	{
		int fa=find(a[i].x),fb=find(a[i].y);
		if(army[fa]&&army[fb]) continue;//会使军队连接
		ans-=a[i].w;
		father[fa]=father[fb];//连接
		army[fa]=army[fb]=army[fa]|army[fb];//计算军队
	}
	printf("%lld",ans);
}

猜你喜欢

转载自blog.csdn.net/Mr_wuyongcong/article/details/83188625
今日推荐