1. 程式人生 > 其它 >複雜樹形DP 題解

複雜樹形DP 題解

複雜樹形DP 題解

Analysis

一張圖

  • 幫助理解題意:左非法,走合法

  • 情況(繞口令):
  1. d ( u , 0 ) d(u,0)
    d(u,0)
    u u u是伺服器,孩子是不是伺服器均可
  2. d ( u , 1 ) d(u,1) d(u,1) u u u不是伺服器, u u u的父親是伺服器, u u u的孩子不能是伺服器
  3. d ( u , 2 ) d(u,2) d(u,2) u u u不是伺服器且 u u u的父親不是伺服器, u u u的孩子必須有且僅有一個是伺服器

狀態轉移方程:

  1. d p [ x ] [ 0 ] = ∑ m i n ( d p [ v ] [ 0 ] , d p [ v ] [ 1 ] ) + 1 , v ∈ s o n s dp[x][0]=\sum min(dp[v][0],dp[v][1])+1,v \in sons
    dp[x][0]=min(dp[v][0],dp[v][1])+1,vsons
  2. d p [ x ] [ 1 ] = ∑ d p [ v ] [ 2 ] , v ∈ s o n s dp[x][1]=\sum dp[v][2],v \in sons dp[x][1]=dp[v][2],vsons
  3. d p [ x ] [ 2 ] = m i n ( d p [ x ] [ 2 ] , d p [ v ] [ 0 ] + ∑ d p [ V i ] [ 2 ] ) dp[x][2]=min(dp[x][2],dp[v][0]+\sum dp[Vi][2]) dp[x][2]=min(dp[x][2]
    ,dp[v][0]+
    dp[Vi][2])
    v ∈ s o n s , i ∈ s o n s , V i ≠ v v \in sons,i \in sons, Vi \neq v vsons,isons,Vi=v
優化狂魔: d p [ x ] [ 2 ] = m i n ( d p [ x ] [ 2 ] , d p [ x ] [ 1 ] − d [ v ] [ 2 ] + d [ v ] [ 0 ] ) , v ∈ s o n s dp[x][2]=min(dp[x][2],dp[x][1]-d[v][2]+d[v][0]),v \in sons dp[x][2]=min(dp[x][2],dp[x][1]d[v][2]+d[v][0]),vsons

CODE

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int NR=1e4+5;
const int MR=1e5+5;
const int INF=0x3f3f3f3f;
const int MOD=1e9+7;
int n,u,v,op;
struct Edge
{
	int v,nxt;
}g[NR<<1];
int fte[NR],gsz;
void adde(int u,int v)
{
	g[++gsz]=(Edge){v,fte[u]};
	fte[u]=gsz;
}
int dp[NR][3];
void dfs(int x,int fa)
{
	
	dp[x][0]=1;
	dp[x][2]=NR;
	for(int i=fte[x];i;i=g[i].nxt)
	{
		int y=g[i].v;
		if(y==fa)
			continue;
		dfs(y,x);
		dp[x][0]+=min(dp[y][1],dp[y][0]);
		dp[x][1]+=dp[y][2];
	}
	for(int i=fte[x];i;i=g[i].nxt)
	{
		int y=g[i].v;
		if(y==fa)
			continue;
		dp[x][2]=min(dp[x][2],dp[y][0]+dp[x][1]-dp[y][2]);
	}
}
void solve()
{
	memset(fte,0,sizeof(fte));
	memset(dp,0,sizeof(dp));
	gsz=0;
    scanf("%d",&n);
	for(int i=1;i<n;++i)
	{
		scanf("%d%d",&u,&v);
		adde(u,v);
		adde(v,u);
	}
	dfs(1,1);
	printf("%d\n",min(dp[1][2],dp[1][0]));
}
int main()
{
	while(1)
	{
		solve();
		scanf("%d",&op);
		if(op==-1)
			break;
	}
	return 0;
}