当前位置:编程学习 > C/C++ >>

HDU 4313

这个题有两种做法

1.并查集

       初始时一条边都不加,将所有边按权值从大到小排序,然后依次判断每一个边两端的顶点是否是均为machine节点,如果是则应删除这条边,否则加入这条边,然后在并查集合并时尽量让根节点为machine节点。
[cpp]
#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节点,那么要留下一个删除费用最大的节点用于向上更新。
[cpp] 
#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)v

补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,