皇宫看守 最小支配集

链接:链接

题意

  • 给一颗树,
  • 最小支配集

思路

  • 和没有上司的舞会有区别,没有上司的舞会是一条边相邻的俩个点至少选一个点属于最小点覆盖
  • 最小点覆盖需要考虑 父节点,子节点,本身节点的状态
  • f[u][0] 表示u节点被父节点的看到的最小花费
  • f[u][1] 表示u节点被子节点看到的最小花费
  • f[u][2] 表示u节点自己被放置的最小花费
  • f[u][0] += sigma min(f[j][1],f[j][2]);
  • f[u][2] += sigma min(f[j][0],f[j][1],f[j][2]);
  • f[u][1] 表示u被他某一个子节点看到;需要枚举所有子节点,然后求最小值
  • f[u][1] =min(f[j][2]+sigma min(f[k][1],f[k][2]);

代码

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1510;

int n;
int h[N], w[N], e[N], ne[N], idx;
int f[N][3];
bool st[N];

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

void dfs(int u)
{
    f[u][2] = w[u];

    int sum = 0;
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        dfs(j);
        f[u][0] += min(f[j][1], f[j][2]);
        f[u][2] += min(min(f[j][0], f[j][1]), f[j][2]);
        sum += min(f[j][1], f[j][2]);
    }

    f[u][1] = 1e9;
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        f[u][1] = min(f[u][1], sum - min(f[j][1], f[j][2]) + f[j][2]);
    }
}

int main()
{
    cin >> n;

    memset(h, -1, sizeof h);
    for (int i = 1; i <= n; i ++ )
    {
        int id, cost, cnt;
        cin >> id >> cost >> cnt;
        w[id] = cost;
        while (cnt -- )
        {
            int ver;
            cin >> ver;
            add(id, ver);
            st[ver] = true;
        }
    }

    int root = 1;
    while (st[root]) root ++ ;

    dfs(root);

    cout << min(f[root][1], f[root][2]) << endl;

    return 0;
}


 posted on 2020-01-31 23:28  谁是凶手1703  阅读(66)  评论(0)    收藏  举报