题目链接:Strategic Game
大意:在一个树的结点上放最少的士兵,使之能覆盖最多的边
两种做法
(1)最小点覆盖=最大匹配(匈牙利)
#include <stdio.h>
#include <vector>
#include <memory.h>
using namespace std;
const int maxn = 1505;
bool vis[maxn];
int link[maxn];
vector<int>g[maxn];
int n;
int dfs(int u){
for (int i = 0; i < g[u].size(); ++i) {
int v = g[u][i];
if (!vis[v]) {
vis[v] = true;
if (link[v] == -1 || dfs(link[v])){
link[v] = u;
return 1;
}
}
}
return 0;
}
int hungry()
{
int res = 0;
memset(link, -1, sizeof(link));
for (int u = 0; u < n; ++u){
memset(vis, 0, sizeof(vis));
res += dfs(u);
}
return res;
}
int main()
{
//freopen("in.txt", "r", stdin);
int a, b, num;
while (scanf("%d", &n) != EOF){
for (int i = 0; i < n; i++) g[i].clear();
for (int i = 0; i < n; ++i) {
scanf("%d:(%d)", &a, &num);
while (num--){
scanf("%d", &b);
g[a].push_back(b);
g[b].push_back(a);
}
}
printf("%d\n", hungry() / 2);
}
return 0;
}
(2)树形DP
d[u][0]表示不选节点v,最小士兵数
d[u[1]表示选节点v,最小士兵数
如果不选u,则一定要选其儿子v,才能覆盖u和v之间的边
如果选u,则选择d[v][0], d[v][1]中最小的一个
#include<stdio.h>
#include<memory.h>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 1505;
vector<int>g[maxn];
int vis[maxn];
int d[maxn][2];
void dfs(int u)
{
d[u][1] = 1;
d[u][0] = 0;
for (int i = 0; i < g[u].size(); ++i){
int v = g[u][i];
if (!vis[v]){
vis[v] = true;
dfs(v);
d[u][0] += d[v][1];
d[u][1] += min(d[v][0], d[v][1]);
}
}
}
int main()
{
//freopen("in.txt", "r", stdin);
int n, a, b, num;
while (scanf("%d", &n) != EOF){
memset(vis, 0, sizeof(vis));
for (int i = 0; i < n; ++i)g[i].clear();
for (int i = 0; i < n; ++i){
scanf("%d:(%d)", &a, &num);
while (num--){
scanf("%d", &b);
g[a].push_back(b);
g[b].push_back(a);
}
}
vis[0] = true;
dfs(0);
printf("%d\n", min(d[0][0], d[0][1]));
}
return 0;
}