您的位置:首页 > 其它

poj 1463 Strategic game 树形dp

2016-08-16 18:31 459 查看
题目简述:

     有若干结点,结点之间有路相连,构成树形结构,如果在一个结点上放置一个士兵,与这个结点相连的路就可以被监视,现在要监视所以的路,问至少要多少士兵。

思路:

最优解结构: dp[i][0],dp[i][1]分别表示不在i结点和在i结点上放置士兵时整个以i结点为根的子树被覆盖用到目标的最少数量。

状态转移:对叶子结点,有

dp[i][0]=0,dp[i][1]=1;

对非叶子结点,有

dp[i][0]=∑(dp[j][1])

dp[i][1]=∑(min(dp[j][0],dp[j][1]))+1    (j为i的子结点)

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define maxn 1508

using namespace std;

int childcnt[maxn], pre[maxn], dp[maxn][2], n;
//dp过程
void DP(int root) {
int i, d1 = 0, d0 = 0;
if(childcnt[root] == 0) {
dp[root][0] = 0;
dp[root][1] = 1;
return;
}
for(i = 0; i < n; i++)
if(pre[i] == root) {
DP(i);
d1 += min(dp[i][0], dp[i][1]);
d0 += dp[i][1];
}
dp[root][1] = d1+1;
dp[root][0] = d0;
}

int main() {
int i, dad, child, m;
while(~scanf("%d", &n)) {
memset(childcnt, -1, sizeof(childcnt));
memset(pre, -1, sizeof(pre));
int root = -1;
for(i = 0; i < n; i++) {
scanf("%d:(%d)", &dad, &m);
childcnt[dad] = m;//记录dad儿子的个数
if(root == -1)
root = dad;
while(m--) {
scanf("%d", &child);
pre[child] = dad;//记录child的父亲结点
}
if(pre[root] == dad)
root = dad;     //找到根结点
}
DP(root);
cout<<min(dp[root][0], dp[root][1])<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: