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
#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]));
}
}