(树形DP)Strategic game POJ - 1463

题意

给你一棵树,树的每一个节点可以守护与其相连的所有边,问你最少用多少个节点可以守护这整棵树

思路

仔细思考不难发现,要想守护一条边,边的两个端点必须有一个可以被选(两个都选也可以),然后这个问题就变成了翻版的没有上司的舞会
定义:dp[i][0]表示不选i,守护其子树需要多少点
   dp[i][0]表示选上i,守护其子树需要多少点
状态转移方程:
    dp[i][0] = ∑dp[j][1] (i为j的父亲节点)
    dp[i][1] = 1+∑min(dp[j][1],dp[j][0]) (i为j的父亲节点)

vetcor忘记清空T了好几次。。。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
 using namespace std;
 const int maxn=1502;
 int dp[maxn][2],n,fa[maxn];//dp[i][0]代表不选i,dp[i][1]代表选i 
 vector<int> edge[maxn];
 void dfs(int x,int fa)
 {
 	dp[x][0]=0,dp[x][1]=1;
	for(int i=0;i<edge[x].size();i++){
		if(edge[x][i]!=fa){
			dfs(edge[x][i],x);
			dp[x][0]+=dp[edge[x][i]][1];
			dp[x][1]+=min(dp[edge[x][i]][0],dp[edge[x][i]][1]);
		}
	} 
 }
 int main()
 {
 	while(scanf("%d",&n)!=EOF){
 		int x,num,y;
 		for(int i=0;i<n;i++)
 			edge[i].clear();
 		for(int i=0;i<n;i++){
 				num=0;
 			scanf("%d:(%d)",&x,&num);
			for(int j=1;j<=num;j++){
				scanf("%d",&y);
				edge[x].push_back(y);
				edge[y].push_back(x);
			}
		 }
		 dfs(0,-1);
		 printf("%d\n",min(dp[0][0],dp[0][1]));
	 }
  } 
发布了13 篇原创文章 · 获赞 1 · 访问量 123

猜你喜欢

转载自blog.csdn.net/weixin_43115940/article/details/103912376
今日推荐