HDU 4313

这个题有两种做法

1.并查集

初始时一条边都不加,将所有边按权值从大到小排序,然后依次判断每一个边两端的顶点是否是均为machine节点,如果是则应删除这条边,否则加入这条边,然后在并查集合并时尽量让根节点为machine节点。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<math.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
int cnt;
int n,k;
ll sum;
bool is[100100];
int fa[100100];
struct Edge{
    int from,to,cost;
}edge[100100];
void addedge(int s,int t,int c){
    edge[cnt].from=s;
    edge[cnt].to=t;
    edge[cnt++].cost=c;
}
void init(){
    cnt=0;
    memset(is,0,sizeof(is));
    for(int i=0;i<n;i++)
        fa[i]=i;
    sum=0;
}
bool cmp(struct Edge a,struct Edge b){
    return a.cost<b.cost;
}
int query(int i){
    if(fa[i]!=i)
        fa[i]=query(fa[i]);
    return fa[i];
}
void merge(int a,int b){
    int aa=query(a);
    int bb=query(b);
    if(is[bb])
        fa[aa]=bb;
    else
        fa[bb]=aa;
}
int main(){
    int t,T,i,j,u,v,w,uu,vv;
    int tem,p,q;
    bool flag;
    scanf("%d",&T);
    for(t=1;t<=T;t++){
        scanf("%d %d",&n,&k);
        init();
        for(i=1;i<n;i++){
            scanf("%d %d %d",&u,&v,&w);
            addedge(u,v,w);
        }
        for(i=1;i<=k;i++){
            scanf("%d",&tem);
            is[tem]=1;
        }
        sort(edge,edge+cnt,cmp);
        for(i=cnt-1;i>=0;i--){
            flag=0;
            uu=query(edge[i].from);
            vv=query(edge[i].to);
            if(uu!=vv && is[uu] && is[vv])
                flag=1;
            if(flag){
                sum+=edge[i].cost;
                //printf("****%d %d %d\n",i,edge[i].from,edge[i].to);
            }
            else
                merge(edge[i].from,edge[i].to);
        }
        cout<<sum<<endl;
    }
}
2.树形DP

这里dis[i]数组保存的是从i节点向下走到machine节点的最小边权,如果i节点本身为machine节点,那么dis[i]=MAX.

当前的根节点如果是machine节点,那么与根节点相连的所有能走到machine节点的节点的都要删去。

当前的根节点如果是machine节点,那么要留下一个删除费用最大的节点用于向上更新。

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std;
const long long MAX=(~(0ULL)>>1);
typedef long long ll;
int cnt,head[100100];
int n,k;
ll sum;
bool is[100100];
ll dis[100100];
vector<ll>vec[100100];
struct Edge{
    int to,cost,next;
}edge[200100];
void addedge(int s,int t,int c){
    edge[cnt].to=t;
    edge[cnt].next=head[s];
    edge[cnt].cost=c;
    head[s]=cnt++;

    edge[cnt].to=s;
    edge[cnt].next=head[t];
    edge[cnt].cost=c;
    head[t]=cnt++;
}
void init(){
    cnt=0;
    memset(head,-1,sizeof(head));
    memset(is,0,sizeof(is));
    sum=0;
    for(int i=0;i<n;i++)
        vec[i].clear();
}
ll mini(ll a,ll b){
    return a>b?b:a;
}
void dfs(int s,int father){
    int i,j;
    int all=0;
    ll s1=0,s2=0;

    for(i=head[s];i!=-1;i=edge[i].next){
        j=edge[i].to;
        if(j!=father){
            dfs(j,s);
            if(is[j])
                vec[s].push_back(mini(dis[j],edge[i].cost));
        }
    }
    if(vec[s].size()==0){
        dis[s]=MAX;
        return;
    }
    sort(vec[s].begin(),vec[s].end());

    for(i=0;i<vec[s].size()-1;i++)
        sum+=(ll)vec[s][i];

    if(is[s]){
        sum+=(ll)vec[s][i];
        dis[s]=MAX;
    }
    else{
        is[s]=1;
        dis[s]=vec[s][i];
    }
}
int main(){
    int t,T,i,j,u,v,w,tem;
    scanf("%d",&T);
    for(t=1;t<=T;t++){
        scanf("%d %d",&n,&k);
        init();
        for(i=1;i<n;i++){
            scanf("%d %d %d",&u,&v,&w);
            addedge(u,v,w);
        }
        for(i=1;i<=k;i++){
            scanf("%d",&tem);
            is[tem]=1;
        }
        memset(dis,0,sizeof(dis));
        dfs(0,-1);
        cout<<sum<<endl;
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值