Time Limit: 2000MS | Memory Limit: 10000K | |
Total Submissions: 5737 | Accepted: 2615 |
Description
Input
Output
Sample Input
4Sample Output
1
2
选尽量少的点覆盖与其关联的边;
/******************************************************************** * 题目:Strategic game * source:POJ * 分类:树形DP专辑 * 题意:题意:给一个无根树,选一些点,选了1个点, * 与该点关联的边都会被覆盖,问要覆盖完所有的边,至少选多少个点 * 分析:dp[u][0],要覆盖u子树的所有边,且u不选的最小花费 * dp[u][1],要覆盖u子树的所有边,且u选的最小花费; * dp[u][0]:因为u不选了,而u和儿子v的连线总是要覆盖的,那只好选所有的儿子, * 才能覆盖这些边 * dp[u][0] = sigma(dp[v][1]); * dp[u][1]:因为u选了,那么u和儿子的边,都被覆盖了,这样儿子选不选问题都行, * 最后都可以覆盖所有边,那么就当然选花费小的 * dp[u][1]=sigma(min(dp[v][0],dp[v][1])); * 边界:对于叶子,dp[leaf][0]=0;dp[leaf][1] = 1; * author:crazy_石头 * 吐槽:跟着G-rated大牛的blog刷不动啊~~略难,只会划水的狗无语了。。。。。 ***************************************************************************/ #include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=1500+5; struct Edge { int to; int next; }edge[maxn<<2]; int dp[maxn][2]; int head[maxn]; bool vis[maxn]; int cnt; int n; inline int max(int a,int b) { return a>b?a:b; } inline int min(int a,int b) { return a<b?a:b; } inline void addedge(int u,int v) { edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt++; } inline void makemap(int from,int to) { addedge(from,to); addedge(to,from); } inline void DFS(int u) { vis[u]=1; dp[u][0]=0; dp[u][1]=1;//边界条件; for(int i=head[u];~i;i=edge[i].next) { int v=edge[i].to; if(!vis[v])//若该点未访问过,访问该点; { DFS(v); dp[u][0]=dp[u][0]+dp[v][1];//更新此时的结果; dp[u][1]=dp[u][1]+min(dp[v][0],dp[v][1]); } } } inline void init() { cnt=0; memset(head,-1,sizeof(head)); memset(vis,0,sizeof(vis)); } int main() { int u,v,t,m; while(scanf("%d",&n)!=EOF) { init(); memset(dp,0,sizeof(dp)); while(n--) { scanf("%d:(%d)",&u,&t); for(int i=0;i<t;i++) { scanf("%d",&v); makemap(u,v); } } DFS(u); printf("%d\n",min(dp[u][0],dp[u][1])); } return 0; }