Codeforces Round #216 (Div. 2), problem: (C) Valera and Elections 【树形dp+dfs】

题意

给出n个点,n-1对关系,表示两点之间是否连通,1为连通,2为断。选中一个点,可以修复1到该点的路径上所有坏的边。求最少要选出哪些点。

思路

由于顶点数比较多,然后带权值,我们采用链式前向星建边,然后dfs。

在回溯的过程中,如果在当前点的儿子存在有问题的边,那就不选这个点

反之,如果没有并且连接这个点的边是有问题的边,这个点就是所求的点。

回溯时情况:

  • 儿子存在有问题的边 不选择这个点 return 1
  • 当前状态为2并且儿子下没有有问题的边,保存这个点 return 1
  • 其他情况 return 0

code

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
const int maxn=2e5+5;
int n,cnt,k;
int head[maxn],vis[maxn];
int ans[maxn],num[maxn];
struct node{
    int to,nex,w;
}e[maxn<<1];
void init(){
    memset(head,-1,sizeof(head));
    cnt=0,k=0;
    memset(vis,0,sizeof(vis));
}
void add(int u,int v,int w){
    e[cnt].to=v;
    e[cnt].nex=head[u];
    e[cnt].w=w;
    head[u]=cnt++;
}
int dfs(int u,int op){
    vis[u]=1;
    for(int i=head[u];~i;i=e[i].nex){
        int v=e[i].to,w=e[i].w;
        if(!vis[v])
            num[u]+=dfs(v,w);
    }
    if(num[u])
        return 1;
    if(op==2&&num[u]==0){
        ans[k++]=u;
        return 1;
    }
    return 0;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n;
    init();
    for(int i=1;i<=n-1;i++){
        int u,v,w;
        cin>>u>>v>>w;
        add(u,v,w);
        add(v,u,w);
    }
    dfs(1,-1);
    cout<<k<<endl;
    if(k){
        for(int i=0;i<k-1;i++)
        cout<<ans[i]<<" ";
        cout<<ans[k-1]<<endl;
    }
    return 0;
}
学如逆水行舟,不进则退
发布了470 篇原创文章 · 获赞 1150 · 访问量 17万+

猜你喜欢

转载自blog.csdn.net/weixin_42429718/article/details/104142608