poj1463 Strategic game
1题目描述很简单。。其实就是求最小点覆盖。。但是。。。他明确说明是树。。如果用矩阵存储。。然后用匈牙利,显然不仅浪费空间。还浪费时间。。TLE了。。。
然后用邻接表。。可以AC了。。。
但是效率还是不高啊。。
这是一道最典型节点覆盖问题,这类可以用树形DP解。
对于顶点i,有两种状态,有士兵,没士兵,将这种状态下以i为根的子树的总士兵数为dp[i][0],dp[i][1]。
显然,如果i点没有士兵,那么它的所有子节点一定要有士兵,否则中间的线不能被覆盖。
所以dp[i][0]=dp[j0][1]+dp[j1][1]+...+dp[jk][1],其中j1,j2,...,jk是i的所有子节点。
如果i点有士兵,那么它的任意子节点都可以有士兵或没有士兵。
所以dp[i][1]=min(dp[j0][0],dp[j0][1])+min(dp[j1][0],dp[j1][1])+...+min(dp[jk][0],dp[jk][1])+1.
对于叶子节点,dp[i][0]=0,dp[i][1]=1
以上就是动态规划的状态转移方程。
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<limits.h> #define MIN(a,b) ((a)<(b)?(a):(b)) #define N 1505 #define M 11 typedef struct { int sum0,sum1; }Sum; Sum save; typedef struct node { int count; struct node * next[M]; }tree; Sum dp(tree * root) { Sum s; int i; s.sum0=0; s.sum1=1; for(i=0;i<root->count;i++) { save=dp(root->next[i]); s.sum0+=save.sum1; s.sum1+=MIN(save.sum1,save.sum0); } return s; } int main(void) { int n,a,m,i,j,v; tree t[N],*root; Sum ans; while(scanf("%d",&n)!=EOF) { memset(t,0,sizeof(t)); root=NULL; for(i=0;i<n;i++) { scanf("%d:(%d)",&a,&m); t[a].count=m; if(root==NULL) { root=&t[a]; } for(j=0;j<m;j++) { scanf("%d",&v); t[a].next[j]=&t[v]; } } ans=dp(root); printf("%d\n",MIN(ans.sum0,ans.sum1)); } return 0; }