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;
}


原文地址:https://www.cnblogs.com/int32bit/p/3187796.html