题意:给出一棵树, 边有两种 类型1, 代表路是好的, 类型2代表路是坏的, 我们要修复所有的路, 当我们修复结点x的时候, 那么它到结点1之间的所有路都会被修复,求最小的修路节点的集合
思路:对于节点x,它到父节点的边为类型2,那么如果节点x的所有子树都不存在类型为2的边,则将节点x加入子集,否则任意一个子树中的边得到维修,x到父节点的边也一定会被维修,这种情况x就不加入子集。
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
const int qq = 1e5+10;
int top=0;
int num[qq];
int dp[qq];
int vis[qq];
struct Node{
int to,type;
};
vector<Node>v[qq];
int dfs(int rt, int flag){
int len = v[rt].size();
int s=0; //s是标记变量, s=0代表其子树中没有类型2的边,否则的话就代表有
vis[rt] = 1; // 返回的变量可以消除标记、
for(int i=0; i<len; ++i){
int son = v[rt][i].to;
if(vis[son]) continue;
if(v[rt][i].type==2) s+=dfs(son, 1);
else s+=dfs(son, 0);
}
if(flag && !s){
num[top++] = rt;
return 1;
}
return s;
}
int main(){
int n;scanf("%d",&n);
Node tmp;
for(int i=0; i<n-1; ++i){
int a,b,c;scanf("%d%d%d",&a,&b,&c);
tmp.to = b;
tmp.type = c;
v[a].push_back(tmp);
tmp.to = a;
v[b].push_back(tmp);
}
dfs(1, 0);
printf("%d\n", top);
for(int i=0; i<top; ++i)
printf("%d ", num[i]);
return 0;
}