树形dp+状态

1.没有上司的舞会
一条边上最多选择一个点

#include
#include
#include
#include
using namespace std;
int num[6100];
int deg[6100];
int dp[6100][2];
int h[6100],ver[6100],ne[6100],cnt=0;
void add(int a,int b)
{
	ver[cnt]=b;
	ne[cnt]=h[a];
	h[a]=cnt++;
}
void dfs(int u,int fa)
{
	dp[u][1]=num[u];
	dp[u][0]=0;
	for(int i=h[u];i!=-1;i=ne[i])
	{
		int y=ver[i];
		if(y==fa) continue;
		dfs(y,u);
		dp[u][1]+=dp[y][0];
		dp[u][0]+=max(dp[y][1],dp[y][0]);
	}
}
int main()
{
	
	int n;
	cin>>n;
	memset(h,-1,sizeof h);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&num[i]);
	}
	for(int i=0;i<n-1;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		add(y,x);
	    deg[x]++;
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		if(!deg[i])
		{
			ans=i;
			dfs(i,0);break;
		}	
	}
	printf("%d\n",max(dp[ans][1],dp[ans][0]));
}

2.战略游戏
一条边上最少选择一个点

#include
#include
#include
#include
using namespace std;
int n;
const int N=2000;
int h[N],e[N*2],ne[N*2],idx;
int deg[N];int dp[N][2];
void add(int a,int b)
{
	e[idx]=b;
	ne[idx]=h[a];
	h[a]=idx++;
}
void dfs(int x)
{
	dp[x][0]=0;dp[x][1]=1;
	for(int i=h[x];i!=-1;i=ne[i])
	{
		int j=e[i];
		dfs(j);
		dp[x][0]+=dp[j][1];
		dp[x][1]=min(dp[j][0]+dp[x][1],dp[j][1]+dp[x][1]);
	}
}
int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		memset(h,-1,sizeof h);
		memset(deg,0,sizeof deg);
		memset(dp,0,sizeof dp);
		idx=0;
		for(int i=0;i<n;i++)
		{
			int x,num;
			scanf("%d:(%d)",&x,&num);
			x++;
			for(int j=1;j<=num;j++)
			{
				int y;
				scanf("%d",&y);y++;
				deg[y]++;
				add(x,y);
			}
		}
		int root=0;
		for(int i=1;i<=n;i++)
		{
			if(deg[i]==0)
			{
				root=i;
				dfs(i); break;
			 } 
		}
		cout<<min(dp[root][1],dp[root][0])<<endl;
	}
	

}
  1. 皇宫看守
    题目:太平王世子事件后,陆小凤成了皇上特聘的御前一品侍卫。

皇宫各个宫殿的分布,呈一棵树的形状,宫殿可视为树中结点,两个宫殿之间如果存在道路直接相连,则该道路视为树中的一条边。

已知,在一个宫殿镇守的守卫不仅能够观察到本宫殿的状况,还能观察到与该宫殿直接存在道路相连的其他宫殿的状况。

大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全天候看守,在不同的宫殿安排看守所需的费用不同。

可是陆小凤手上的经费不足,无论如何也没法在每个宫殿都安置留守侍卫。

帮助陆小凤布置侍卫,在看守全部宫殿的前提下,使得花费的经费最少。

#include
#include
#include
#include
using namespace std;
const int N=2000;
int a[N],h[N],e[N*2],ne[N*2],idx;
int deg[N];
int dp[N][3];
void add(int a,int b)
{
	e[idx]=b;
	ne[idx]=h[a];
	h[a]=idx++;
}
//dp[x][0]被父节点看到
//dp[x][1]被子节点看到
//dp[x][2]在x节点放 
void dfs(int x)
{
	dp[x][0]=0;
	dp[x][2]=a[x];
	int sum=0;
	for(int i=h[x];i!=-1;i=ne[i])
	{
		int j=e[i];
		dfs(j);
		dp[x][0]+=min(dp[j][2],dp[j][1]);
		dp[x][2]+=min(dp[j][1],min(dp[j][0],dp[j][2]));
		sum+=min(dp[j][1],dp[j][2]);
	}
	dp[x][1]=1e9;
	for(int i=h[x];i!=-1;i=ne[i])
	{
		int j=e[i];
		dp[x][1]=min(dp[x][1],sum-min(dp[j][1],dp[j][2])+dp[j][2]);
	}
}
int main()
{
	int n;
	cin>>n;
	int num,x;
	memset(h,-1,sizeof h);
	for(int i=1;i<=n;i++)
	{
	    int ans;
		scanf("%d%d%d",&x,&ans,&num);
		a[x]=ans;
		for(int j=1;j<=num;j++)
		{
			int y;scanf("%d",&y);
			deg[y]++;
			add(x,y);
		}
	}
	int root;
	for(int i=1;i<=n;i++)
	{
		
		if(!deg[i])
		{
			root=i;
			dfs(i);
			break;
		}
		
	}
	cout<<min(dp[root][2],dp[root][1])<<endl;
}

你可能感兴趣的:(树形dp)