SPOJ PT07X Vertex Cover(树形dp)

来源:互联网 发布:linux rsync 相互同步 编辑:程序博客网 时间:2024/06/06 05:43

题目链接:
SPOJ PT07X Vertex Cover
题意:
一个无向无环图,给n个节点和n1条边,求选择最小的顶点数量使得每条边至少有一个顶点被选中,输出顶点数量。
数据范围:n105
分析:
对于节点i,定义dp[i][0]i没被选中时将i子树的所有边都覆盖时的最少点数,定义dp[i][1]i被选中时的最优解。
状态转移方程:

dp[u][0]=dp[v][1]vu

dp[u][1]=min(dp[v][0],dp[v][1])vu

需要在dfs记录从父节点转移时父节点的父节点是谁,防止死循环。选择任意点为起点递归应该都可以。

#include <stdio.h>#include <string.h>#include <algorithm>#include <math.h>using namespace std;typedef long long ll;const int MAX_N = 100010;int n, total;int head[MAX_N], dp[MAX_N][2], vis[MAX_N];struct Edge {    int to, next;}edge[MAX_N * 2];inline void AddEdge(int from, int to){    edge[total].to = to;    edge[total].next = head[from];    head[from] = total++;}void dfs(int u, int p){    if (vis[u]) return;    vis[u] = 1;    dp[u][1] = 1, dp[u][0] = 0;    for (int i = head[u]; i  != -1; i = edge[i].next) {        int v = edge[i].to;        if (v == p) continue;        dfs(v, u);        dp[u][0] += dp[v][1];        dp[u][1] += min(dp[v][1], dp[v][0]);    }}int main(){    while (~scanf("%d", &n)) {        memset(head, -1, sizeof(head));        total = 0;        for (int i = 1; i < n; ++i) {            int u, v;            scanf("%d%d", &u, &v);            AddEdge(u, v);            AddEdge(v, u);        }        memset(vis, 0, sizeof(vis));        dfs(1, 0);        printf("%d\n", min(dp[1][0], dp[1][1]));    }    return 0;}
0 0