jzoj3347,bzoj3257-[NOI2013模拟]树的难题【树形dp】

正题

B Z O J BZOJ BZOJ题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3257


题目大意

一棵树上的节点有 3 3 3种颜色,有边权。

选择一些边割掉使得森林中每棵树只有一个白点或没有黑点。

求割掉的边的最小值。


解题思路

定义 f i , s t a t e f_{i,state} fi,state表示 i i i的子树中割掉后森林所有的树都满足条件且目前子树连接的点状态为 s t a t e state state

下面给出状态

状态
0 0 0 0 0 0 0 0 0
1 1 1 0 ∼ ∞ 0\sim \infty 0 0 0 0
2 2 2 0 0 0 0 ∼ ∞ 0\sim \infty 0
3 3 3 0   o r   1 0\ or\ 1 0 or 1 0 0 0
4 4 4 0   o r   1 0\ or\ 1 0 or 1 0 ∼ ∞ 0\sim \infty 0

然后如果对于状态 s 1 s1 s1 s 2 s2 s2。若 s 1 s1 s1可以转移到 s 2 s2 s2

f x , s 1 = f x , s 1 + f y , s 2 f_{x,s1}=f_{x,s1}+f_{y,s2} fx,s1=fx,s1+fy,s2

否则
f x , s 1 = f x , s 1 + f y , s 2 + w x , y f_{x,s1}=f_{x,s1}+f_{y,s2}+w_{x,y} fx,s1=fx,s1+fy,s2+wx,y

然后要注意后两个状态的白色只能传一个白色上来所有需要特殊处理

需要注意的是在野鸡 j z o j jzoj jzoj中会爆栈,这里是先进行一次拓扑排序再 d p dp dp


c o d e code code

#include
#include
#include
#define xf(z) f[x][z]
#define yf(z) f[y][z]
#define min3(a1,a2,a3) min(min(a1,a2),a3)
#define min4(a1,a2,a3,a4) min(min(a1,a2),min(a3,a4))
#define min5(a1,a2,a3,a4,a5) min(min(min(a1,a2),min(a3,a4)),a5)
#define ll long long
using namespace std;
const ll N=301000,inf=1e18;
struct Edge_node{
	ll to,next,w;
}a[N*2];
ll T,n,c[N],ls[N],tot,f[N][5],q[N],fa[N];
void addl(ll x,ll y,ll w)
{
	a[++tot].to=y;
	a[tot].next=ls[x];
	ls[x]=tot;
	a[tot].w=w;
}
void dfs()
{
	int head=1,tail=0;
	q[++tail]=1;
	while(head<=tail)
	{
		int x=q[head++];
		for(int i=ls[x];i;i=a[i].next)
		{
			int y=a[i].to;
			if(y==fa[x]) continue;
			fa[y]=x;q[++tail]=y;
		}
	}
	for(int i=tail;i>=1;i--)
	{
		int x=q[i];
		ll white1=0,white2=0;
		for(ll i=ls[x];i;i=a[i].next)
		{
			ll y=a[i].to,z;
			if(y==fa[x]) continue;
			xf(0)+=min(min4(yf(1),yf(2),yf(3),yf(4))+a[i].w,yf(0));
			xf(1)+=min(min3(yf(0),yf(1),yf(2)),min(yf(3),yf(4))+a[i].w);
			xf(2)+=(z=min(yf(0),min4(yf(1),yf(2),yf(3),yf(4))+a[i].w));
			white1=max(white1,z-yf(2));
			xf(3)+=(z=min(min(yf(0),yf(4)),min3(yf(3),yf(2),yf(1))+a[i].w));
			white2=max(white2,z-min(yf(3),yf(2)));
			xf(4)+=min(min(yf(0),yf(4)),min3(yf(1),yf(2),yf(3))+a[i].w);
		}
		xf(2)-=white1;xf(3)-=white2;
		if(c[x]==1){
			xf(3)=xf(4);xf(2)=xf(0);
			xf(1)=min3(xf(0),xf(1),xf(2));
			xf(0)=xf(4)=inf;
		}
		else if(c[x]==0){
			xf(3)=min3(xf(3),xf(2),xf(0));
			xf(0)=xf(1)=xf(2)=inf;
		}
		xf(1)=min3(xf(1),xf(0),xf(2));
		xf(2)=min(xf(2),xf(0));
		xf(3)=min3(xf(3),xf(2),xf(0));
		xf(4)=min(xf(4),xf(0));
	}
}
int main()
{
	scanf("%lld",&T);
	while(T--)
	{
		memset(f,0,sizeof(f));
		memset(ls,0,sizeof(ls));
		tot=0;
		scanf("%lld",&n);
		for(ll i=1;i<=n;i++)
			scanf("%lld",&c[i]);
		for(ll i=1;i<n;i++)
		{
			ll x,y,w;
			scanf("%lld%lld%lld",&x,&y,&w);
			addl(x,y,w);addl(y,x,w);
		}
		dfs();
		printf("%lld\n",min5(f[1][0],f[1][1],f[1][2],f[1][3],f[1][4]));
	}
}

你可能感兴趣的:(dp)