P2899 [USACO08JAN]手机网络Cell Phone Network

题意:

一棵 n 个点的无权树,求最?点覆盖

 

思路:

那么,我们考虑一个结点可以被谁染色,不难想出,可以有3种情况:被自己染色,被儿子染色,被父亲染色

我们不妨设:

f[i][0] 代表被自己染色      f[i][1] 代表被父亲染色       f[i][2] 代表被儿子染色

设当前节点是 u ,儿子节点是 v

我们来考虑下转移方程:

1自己被自己染色

这时我们可以想一下,u被自己染色可以由什么转移过来,如果u已经被自己染色了的话,他的儿子v可以选择自己染色,也可以选择被自己的儿子染色,当然也可以被u染色,当然,我们要选最小的,所以转移方程就是

f[u][0] += min(f[v][0],f[v][1],f[v][2] )

 

2被自己的父亲结点染色

如果被父亲结点(fa)染色了,那么u的儿子v只能选择自己染色或者被它的儿子染色,转移方程为

f[u][1] += min(f[v][1],f[v][0] )

 

 

3被自己的儿子结点染色

这是最麻烦的一种情况,因为u可能有多个儿子,只要有一个儿子自己染色了,就可以将u覆盖,这种情况就成立了

而现在它的儿子有两种情况,分别是自己染色和被它儿子染色

我们可以先假设每个儿子都是被它自己染色(v被自己染色)的,然后看一下u的每个儿子(v)被其儿子染色是否使结果变得更小,把能让结果更小的 自己染色(v自己染色)的儿子 替换为 被其儿子染色的儿子(v被它儿子染色)的儿子

 

P2899 [USACO08JAN]手机网络Cell Phone Network

 

 

#include <iostream>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
#include <map>
#include <stack>
#include <set>
#include <queue>
#include <math.h>
#include <cstdio>
#include <iomanip>
#include <time.h>
#include <bitset>
#include <cmath>

#define LL long long
#define INF 0x3f3f3f3f
#define ls nod<<1
#define rs (nod<<1)+1

const double eps = 1e-10;
const int maxn = 1e5 + 10;
const LL mod = 1e9 + 7;

int sgn(double a){return a < -eps ? -1 : a < eps ? 0 : 1;}
using namespace std;

struct edge {
    int v,nxt;
}e[maxn << 1];

int head[maxn];
int cnt;
int f[maxn][3];


inline void add_edge(int u,int v) {
    e[++cnt].v = v;
    e[cnt].nxt = head[u];
    head[u] = cnt;
}

void dfs(int u,int fa) {
    f[u][0] = 1;
    int tot = 0;
    int g[maxn];
    for (int i = head[u];~i;i = e[i].nxt) {
        int v = e[i].v;
        if (v == fa)
            continue;
        dfs(v,u);
        f[u][0] += min(f[v][0],min(f[v][1],f[v][2]));
        f[u][1] += min(f[v][0],f[v][2]);
        f[u][2] += f[v][0];
        g[++tot] = f[v][2] - f[v][0];
    }
    if (!tot)
        f[u][2] = INF;
    else {
        sort(g+1,g+1+tot);
        for (int i = 1;i < tot;i++) {
            if (g[i] < 0)
                f[u][2] += g[i];
            else
                break;
        }
    }
}


int main() {
    cnt = 0;
    memset(head,-1, sizeof(head));
    int n;
    cin >> n;
    for (int i = 1;i < n;i++) {
        int u,v;
        cin >> u >> v;
        add_edge(u,v);
        add_edge(v,u);
    }
    dfs(1,0);
    cout << min(f[1][0],f[1][2]) << endl;
    return 0;
}

 

 

P2899 [USACO08JAN]手机网络Cell Phone Network

上一篇:vue中的axios请求


下一篇:P2015 二叉苹果树