Problem:
给了一棵树,所有的边都需要士兵看守,士兵在节点上,结点上的士兵可以看守与他相邻的路,问这棵树最少需要多少士兵。
Solution:
从树顶往下看,如果这个节点没有士兵,则儿子结点必须有士兵,这样才能保证父子边上有人看守,如果这个节点有士兵,那么儿子结点可以有也可以没有士兵,那么问题就转化成了看这两种情况下儿子结点的那个值小,变成了树形的dp问题。
notes:
数据结构为一个二维数组存点边之间的关系,一个数组存每一个节点的权值。
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<string>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<ctime>
#include<vector>
#include<fstream>
#include<list>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define ms(s) memset(s,0,sizeof(s))
const double PI = 3.141592653589;
const int INF = 0x3fffffff;
struct Node {
int fw = 0, tw = 1;
bool hasView = false;
};
vector<Node> nodes;
vector<vector<int> > G;
int dp(int name, int flag) {//flag为1代表选,0代表不选
Node &tnode = nodes[name];
if(!tnode.hasView) {
for(int i = 0; i < G[name].size(); i++) {
tnode.fw += dp(G[name][i], 1);
tnode.tw += min(dp(G[name][i], 1), dp(G[name][i], 0));
}
tnode.hasView = true;
}
if(flag == 1)
return tnode.tw;
else
return tnode.fw;
}
int main() {
// freopen("/Users/really/Documents/code/input","r",stdin);
// freopen("/Users/really/Documents/code/output","w",stdout);
ios::sync_with_stdio(false);
int n, boss, son, father, ns;
while(scanf("%d", &n) != EOF) {
G.clear(); G.resize(n+5);
nodes.clear(); nodes.resize(n+5);
for(int i = 0; i < n; i++) {
scanf("%d:(%d)", &father, &ns);
if(i == 0)
boss = father;
while(ns--) {
scanf("%d", &son);
G[father].push_back(son);
}
}
printf("%d\n", min(dp(boss, 1), dp(boss, 0)));
}
return 0;
}