题目链接: C. Valera and Elections
题目大意:
给出n个点,n-1对关系,表示两点之间是否连通,1为连通,2为断。选中一个点,可以修复1到该点的路径上所有坏的边。求最少要选出哪些点。
思路:
这题还是用dfs,不过做题目的时候还是不会的,看了题解才补了。如果一个点到其父亲的点是坏的,并且他的子节点中所有路径都是好的,那么该点就必须选中。(选出所有路径中最后一条坏的边,只要选中这个点,那么上面所有点都能被修复) 最主要是不知道如何建树,看了题解才知道用vector来建树。 解题过程,存下每一条边,然后dfs建树,用ans数组存答案,(初始化为0,经过标记为2,被选中标记为1)对没条边进行判断,如果是坏的,将这点的ans标记成1,往上搜素,将经过的ans都标记成2,直到根节点1。对每条坏的边都搜素.最后得到答案。
部分细节注释在代码
代码
#include<iostream>
#include<vector>
#include<string>
#include<cstring>
using namespace std;
const int maxn = 100100;
typedef vector<int>V;
V node[maxn]; //存子节点
int vis[maxn], par[maxn], ans[maxn]; //par存父节点 vis用来建树的时候标记是否走过 ,ans存答案。
//存边
struct road {
int f, t, tp;
}q[maxn];
//建树
void dfs(int rt) {
vis[rt] = 1;
for (int i = 0; i<node[rt].size(); ++i) {
if (!vis[node[rt][i]]) {
par[node[rt][i]] = rt;
dfs(node[rt][i]);
}
}
}
int main() {
memset(vis, 0, sizeof(vis));
memset(ans, 0, sizeof(ans));
int n, i, j, a, b, c;
cin >> n;
for (i = 0; i<n - 1; ++i) {
cin >> q[i].f >> q[i].t >> q[i].tp;
node[q[i].f].push_back(q[i].t);
node[q[i].t].push_back(q[i].f);
}
dfs(1);
for (i = 0; i<n - 1; ++i) {
//该边坏了
if (q[i].tp == 2) {
int pt;
//判断哪个点是子节点
if (par[q[i].f] == q[i].t)pt = q[i].f;
else pt = q[i].t;
if (ans[pt] == 0) {
ans[pt] = 1;
pt = par[pt];
//如果该点不是这条路径上损坏的最后一个点 当最后一个点循环搜素的时候前面的点就会被覆盖
while (ans[pt] <= 1) {
ans[pt] = 2;
if (pt == 1)break;
pt = par[pt];
}
}
}
}
int res = 0;
for (i = 1; i <= n; ++i)
if (ans[i] == 1)res++;
cout << res << endl;
int flag = 1;
for (i = 1; i <= n; ++i)
if (ans[i] == 1)
if (flag) {
cout << i;
flag = 0;
}
else cout << " " << i;
return 0;
}