您的位置:首页 > 其它

hdu 4313 - Matrix(最小生成树,并查集)

2013-10-03 20:44 513 查看
题目:

Matrix

题意:
N个点N-1条无向边,K个数,要求去掉一些边,使得这K个数相互不可达,求去掉的边的权值和的最小值

思路:

这K个数不能相互到达,说明这k个数分别属于不同的集合,我们把可以放进同一集合的数作为同一集合,不能放进的,则把这条边舍弃。集合自然想到用并查集。要找最小值,我们可以把所有边按权值从大到小排序,顺序寻找,找到不能放进的则跳过,res+=w,能放进的则进行合并(由于我们其实是找的能够合并的边,只是顺路找不能合并的,所以从大到小排序,大的先合并了,剩余的不能合并的就小了) , 取权值构造图,自然想到最小生成树。

代码:

克鲁斯卡尔算法:

//#pragma comment(linker, "/STACK:102400000,102400000")
#include "iostream"
#include "cstring"
#include "algorithm"
#include "cmath"
#include "cstdio"
#include "sstream"
#include "queue"
#include "vector"
#include "string"
#include "stack"
#include "cstdlib"
#include "deque"
#include "fstream"
#include "map"
using namespace std;
typedef long long LL;
const int INF = 522133279;
const int MAXN = 1000000+100;
#define eps 1e-14
const int mod = 100000007;

int set[100000+100];

struct edge
{
int s;
int e;
int w;

bool operator <(const edge&b)const
{
return w > b.w;
}
} e[100000+100];

int des[100000+100];                //1 - 是剔除点 0 - 非剔除点
int n,k;

int find(int x)
{
return set[x] != x ? set[x] = find(set[x]) : x;
}

int merger(int x , int y)
{
return ((x = find(x)) != (y = find(y))) && (set[x]=y);
}

LL ckru(int n)
{
sort(e,e+n-1);

LL res = 0;

for(int i = 0 ; i < n-1 ; i++)
{
int u = find(e[i].e);
int v = find(e[i].s);

if(!des[u] || !des[v])          //如果不是两个都是剔除点,则合并,注意正常点应该被剔除点合并
{
if(des[v])
merger(u,v);
else if(des[u])
merger(v,u);
else
merger(u,v);
}

else if(des[u] && des[v])       //如果两个都是剔除点,那么这条边不应该被加进去,也就是它应该被销毁
res += e[i].w;
}

return res;
}

int main()
{
//freopen("in","r",stdin);
//freopen("out","w",stdout);

int t;
scanf("%d" , &t);

while(t--)
{
memset(des,0,sizeof(des));

scanf("%d%d",&n,&k);

for(int i = 0 ; i <= n ; i++)
set[i]=i;

for(int i = 0 ; i <  n-1 ; i++)
scanf("%d%d%d" , &e[i].s,&e[i].e,&e[i].w);

for(int i = 0 ; i < k ; i++)
{
int tmp;
scanf("%d" , &tmp);
des[tmp]=1;
}

printf("%I64d\n", ckru(n));
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hdu 最小生成树 图论