1. 程式人生 > >【BZOJ3935】Rbtree 樹形DP

【BZOJ3935】Rbtree 樹形DP

ron size [1] 挖礦 brush val nbsp 結點 它的

【BZOJ3935】Rbtree

Description

給定一顆 N 個點的樹,樹上的每個點或者是紅色,或者是黑色。 每個單位時間內,你可以任選兩個點,交換它們的顏色。 出於某種惡趣味,你希望用最少的時間調整結點的顏色,使得對於每個點,離它最近的黑色點與它的距離不超過 x。

Input

輸入的第一行包含整數 N 和 x(1 <= x <= 10^9)。 接下來一行 N 個整數 C1-Cn,表示結點的初始顏色。1 表示黑色,0 表示紅色。 接下來 N-1 行,每行 3 個整數 ui, vi,wi(1 <= wi <= 10^9),表示點 ui 和 vi 之間存在權值為 wi的邊。

Output

輸出一個數表示答案;如果無解,輸出 “-1”。

Sample Input

3 2
1 0 0
1 2 2
2 3 2

Sample Output

1

HINT

數據規模和約定 對於100%的數據 N<=500

題解:大神們寫的都是單純形?算了我只知道樹形DP。

本題的思路和小奇挖礦相同。用f[x][a][b]表示在x的子樹中放a個黑點,且距離x最近的黑點是b的最小花費(即有多少點從白點變成黑點)。轉移時,對於a那維相當於樹形背包,我們考慮b那維怎麽轉移。

如果我們想用f[y][..][c]來更新f[x][..][b],那麽討論:如果b==c,直接轉移即可;如果c在y的子樹中,那麽用f[y][..][c]的最大值來更新f[x][..][b]即可;如果c不在y的子樹中,那麽我們將b換成c或者將c換成b一定不會變的更差,所以:不用轉移!

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
int n,m,ans,cnt;
ll K;
int v[505],p[505],q[505],Q[505],siz[505],g[505][505],to[1010],next[1010],head[505];
int f[505][505][505];
ll dis[505][505],val[1010];
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)	f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+(gc^‘0‘),gc=getchar();
	return ret*f;
}
inline void add(int a,int b,int c)
{
	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
void dfs1(int x,int fa,int y)
{
	if(y==1)	p[x]=++p[0],Q[p[0]]=x;
	for(int i=head[x];i!=-1;i=next[i])	if(to[i]!=fa)	dis[to[i]][y]=dis[x][y]+val[i],dfs1(to[i],x,y);
	if(y==1)	q[x]=p[0];
}
void dfs2(int x,int fa)
{
	int i,y,j,k,a,mn;
	siz[x]=1;
	for(a=1;a<=n;a++)	if(a!=x&&dis[a][x]<=K)	f[x][0][a]=0;
	f[x][1][x]=!v[x];
	for(i=head[x];i!=-1;i=next[i])	if(to[i]!=fa)
	{
		y=to[i],dfs2(y,x);
		memset(g,0x3f,sizeof(g));
		for(j=0;j<=siz[x]&&j<=m;j++)	for(k=0;k<=siz[y]&&j+k<=m;k++)
		{
			mn=0x3f3f3f3f;
			for(a=p[y];a<=q[y];a++)	mn=min(mn,f[y][k][Q[a]]);
			for(a=1;a<=n;a++)	g[j+k][a]=min(g[j+k][a],f[x][j][a]+f[y][k][a]);
			for(a=1;a<p[y];a++)	g[j+k][Q[a]]=min(g[j+k][Q[a]],f[x][j][Q[a]]+mn);
			for(a=q[y]+1;a<=n;a++)	g[j+k][Q[a]]=min(g[j+k][Q[a]],f[x][j][Q[a]]+mn);
		}
		siz[x]+=siz[y];
		for(j=0;j<=siz[x]&&j<=m;j++)	for(a=1;a<=n;a++)	f[x][j][a]=g[j][a];
	}
}
int main()
{
	n=rd(),K=rd();
	int i,a,b,c;
	memset(head,-1,sizeof(head));
	for(i=1;i<=n;i++)	v[i]=rd(),m+=v[i];
	for(i=1;i<n;i++)	a=rd(),b=rd(),c=rd(),add(a,b,c),add(b,a,c);
	for(i=1;i<=n;i++)	dfs1(i,0,i);
	memset(f,0x3f,sizeof(f));
	dfs2(1,0);
	ans=1<<30;
	for(i=1;i<=n;i++)	ans=min(ans,f[1][m][i]);
	printf("%d",ans>n?-1:ans);
	return 0;
}

【BZOJ3935】Rbtree 樹形DP