http://poj.org/problem?id=1463
对于树形DP不大来感啊,才开始做的时候考虑成覆盖全部点了,致使我拓扑做了,WA了好几次。感觉是树形DP好像以前做过类似的题目可是就是想不出来怎么做了,看来还是不扎实。最后搜了一下解题报告,对于每一点只有放与不放两种状态,如果这一点放了士兵那么他的临接点可以放也可以不放,如果这一点没有放那么他的临接点一定放了。
由此得出dp[i][0]+= dp[j][1] dp[i][1] = min(dp[j][0],dp[j][1]) (j属于i的临接点) dp[i][0] 表示i点不放士兵 dp[i][1] 表示i 点放士兵。。随便由一点出发,进行dp..这里选择0 则最后结果就是min(dp[0][0],dp[0][1]); 用临界矩阵回TLE的,所以要用临界表
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <iostream> #include <cstring> #include <cstdio> #include <vector> #define maxn 1507 using namespace std; int dp[maxn][2]; int n; vector<int>map[maxn]; bool isL(int x) { if (map[x].size() == 1) return true; else return false; } void dfs(int pos,int f) { int i; if (isL(pos) && f != -1)//注意这里f != -1 的判断 { dp[pos][0] = 0; dp[pos][1] = 1; return ; } else { dp[pos][1]++;//注意要先加+1 for (i = 0; i < map[pos].size(); ++i) { if (map[pos][i] != f) { int p = map[pos][i]; dfs(p,pos); dp[pos][0] += dp[p][1]; dp[pos][1] += min(dp[p][1],dp[p][0]); } } } } int main() { //freopen("in.txt","r",stdin); int i,j; int x,y,m; while (~scanf("%d",&n)) { for (i = 0; i < n; ++i) map[i].clear(); memset(dp,0,sizeof(dp)); for (i = 0; i < n; ++i) { scanf("%d:(%d)",&x,&m); for (j = 0; j < m; ++j) { scanf("%d",&y); map[x].push_back(y); map[y].push_back(x); } } dfs(0,-1); printf("%d\n",min(dp[0][0],dp[0][1])); } return 0; }