http://poj.org/problem?id=1463
题目大意:有若干节点,节点之间有路相连,构成树形结构,如果在一个节点上放置一个士兵,与这个节点相连的路就可以被监视,现在要监视所有的路,问至少要多少士兵。
最优解结构:dp[i][0],dp[i][1]分别表示不在i节点上和在i节点上放置士兵时整个以i节点为根的子树被覆盖用到的最少士兵数目。
状态转移方程:
对叶子节点,有
dp[i][1] = 1; dp[i][0] = 0;
对非叶子节点,有
dp[i][1] = ∑(dp[j][1] , dp[j][0]);
dp[i][0] = ∑(dp[j][1])。(j为i的叶子节点)
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <set> #include <map> #include <cmath> #include <queue> using namespace std; template <class T> void checkmin(T &t,T x) {if(x < t) t = x;} template <class T> void checkmax(T &t,T x) {if(x > t) t = x;} template <class T> void _checkmin(T &t,T x) {if(t==-1) t = x; if(x < t) t = x;} template <class T> void _checkmax(T &t,T x) {if(t==-1) t = x; if(x > t) t = x;} typedef pair <int,int> PII; typedef pair <double,double> PDD; typedef long long ll; #define foreach(it,v) for(__typeof((v).begin()) it = (v).begin(); it != (v).end ; it ++) const int N = 1505 , M = 2020; int n , u , v , num; int dp[N][2]; struct Edge { int v , next; Edge() {} Edge(int v,int next) :v(v),next(next) {} }edge[M]; int E , head[N]; void init() { E = 0; memset(head,-1,sizeof(head)); } void addedge(int u,int v) { edge[E] = Edge(v , head[u]); head[u] = E++; } void dfs(int u,int fa) { dp[u][1] = 1; dp[u][0] = 0; int flag = 0; for(int i=head[u];i!=-1;i=edge[i].next) { int v = edge[i].v; if(v == fa) continue; flag = 1; dfs(v , u); dp[u][1] += min(dp[v][0],dp[v][1]); dp[u][0] += dp[v][1]; } } bool ok[N]; int main() { while(~scanf("%d",&n)) { init(); for(int i=0;i<n;i++) ok[i] = 1; for(int i=0;i<n;i++) { scanf("%d:(%d)",&u,&num); while(num --) { scanf("%d",&v); addedge(u,v); ok[v] = 0; } } for(int i=0;i<n;i++) { if(ok[i]) { dfs(i , -1); printf("%d\n" , min(dp[i][0] , dp[i][1])); break; } } } return 0; }