洛谷 P2016 战略游戏

洛谷 P2016 战略游戏

Description

  • Bob喜欢玩电脑游戏,特别是战略游戏。但是他经常无法找到快速玩过游戏的办法。现在他有个问题。

    他要建立一个古城堡,城堡中的路形成一棵树。他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能了望到所有的路。

    注意,某个士兵在一个结点上时,与该结点相连的所有边将都可以被了望到。

    请你编一程序,给定一树,帮Bob计算出他需要放置最少的士兵.

Input

  • 第一行 N,表示树中结点的数目。

    第二行至第N+1行,每行描述每个结点信息,依次为:该结点标号i,k(后面有k条边与结点I相连)。

    接下来k个数,分别是每条边的另一个结点标号r1,r2,...,rk。

    对于一个n(0<n<=1500)个结点的树,结点标号在0到n-1之间,在输入数据中每条边只出现一次。

Output

  • 输出文件仅包含一个数,为所求的最少的士兵数目。

Sample Input

4
0 1 1
1 2 2 3
2 0
3 0

Sample Output

1

题解:

  • 摘抄自pengym大大

  • 这题其实有几种方法,其中比较显而易见的或许是树形dp吧,楼下有很多大佬已经解释过了,(这里

    就不再说了),仔细一看题就可以发现这是一个典型的最小点覆盖。最小点覆盖指的是在一个图中:一个点

    覆盖与之连接的边,求用最少的点可以覆盖。这和题目要求一模一样。同时还有一个定理,最小点覆盖=

    最大匹配数。如果是无向图则/2。因此就很容易想到打匈牙利算法了。

#include <iostream>
#include <cstdio>
#include <cstring>
#define N 1505
using namespace std;

struct E {int next, to;} e[N * N * 2];
int n, num, ans;
int h[N], mat[N];
bool vis[N];

int read()
{
    int x = 0; char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
    return x;
}

void add(int u, int v)
{
    e[++num].next = h[u];
    e[num].to = v;
    h[u] = num;
}

bool dfs(int x)
{
    for(int i = h[x]; i != 0; i = e[i].next)
        if(!vis[e[i].to])
        {
            vis[e[i].to] = 1;
            if(!mat[e[i].to] || dfs(mat[e[i].to]))
            {
                mat[e[i].to] = x;
                return 1;
            }
        }
    return 0;
}

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
        int u = read() + 1, k = read();
        for(int i = 1; i <= k; i++)
        {
            int v = read() + 1;
            add(u, v), add(v, u);
        }
    }
    for(int i = 1; i <= n; i++)
    {
        memset(vis, 0, sizeof(vis));
        if(dfs(i)) ans++;
    }
    cout << ans / 2;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/BigYellowDog/p/11583852.html