题意:
给你一棵树,树的每一个节点可以守护与其相连的所有边,问你最少用多少个节点可以守护这整棵树
思路:
仔细思考不难发现,要想守护一条边,边的两个端点必须有一个可以被选(两个都选也可以),然后这个问题就变成了翻版的没有上司的舞会
定义: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])); } }