洛谷 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;
}