您的位置:首页 > 其它

HDU 4313 Matrix

2012-09-15 11:40 465 查看
题意: n个点的一棵树,其中有k个敌人所在结点,要破坏一些边使得这 k 个点互不可达,求出破坏边的最小权值和。

分析: 对于有n个结点的树,删除任意的k (k<=n-1)条边都能将原树分成k+1个部分

按照题意至少需要将原树划分成 k 个部分(此时每部分中都包含一个敌人的点),删除的边数为k-1。

类似kruskal最小生成树的过程,不过此处将边按权值从大到小排列,每次将边加进来时要判断是否会使两个危险的

点连通,是的话这条边就是需要被删除的,否则将它加到树上。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
#define maxn 100005
#define clr(x)memset(x,0,sizeof(x))
int n,m;
int u[maxn],v[maxn],w[maxn];
int r[maxn],f[maxn];
int find(int x)
{
return f[x]==x?x:(f[x]=find(f[x]));
}
void join(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
{
if(fx<fy)
f[fy]=fx;
else f[fx]=fy;
}
}
bool cmp(int a,int b)
{
return w[a]>w[b];
}
int pos[maxn];
__int64 kruskal()
{
int i;
__int64 res=0;
for(i=0;i<n;i++)
f[i]=i;
for(i=0;i<n-1;i++)
r[i]=i;
sort(r,r+n-1,cmp);
for(i=0;i<n-1;i++)
{
int e=r[i];
int fx=find(u[e]);
int fy=find(v[e]);
if(pos[fx]&&pos[fy])
{
res+=w[e];
continue;
}
if(pos[fx]||pos[fy])
pos[fx]=pos[fy]=1;
join(fx,fy);
}
return res;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
int i,a,b,c;
for(i=0;i<n-1;i++)
{
scanf("%d%d%d",&a,&b,&c);
u[i]=a;
v[i]=b;
w[i]=c;
}
clr(pos);
for(i=0;i<m;i++)
{
int tmp;
scanf("%d",&tmp);
pos[tmp]=1;
}
printf("%I64d\n",kruskal());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: