CF375E Red and Black Tree

Link
单纯形是不可能的,这辈子都不可能单纯形的。
考虑树形dp,设(f_{u,k,p})为在(u)子树内选(k)个黑点,(u)选的黑点是(p)的最小代价。
转移和树形背包差不多,不妨设(vin son_u),考虑合并(f_{u,i,p},f_{v,j,q})
(p=q),则(f_{u,i,p}+f_{v,j,p} ightarrow f_{u,i+j,p})
(q)(v)子树内,则此时(p)一定不在(v)子树内,(f_{u,i,p}+f_{v,j,q} ightarrow f_{u,i+j,p})
(q)(v)子树外,不难发现此时若(p e q)则一定不优,因此不予考虑。

#include<cstdio>
#include<vector>
#include<cstring>
#include<utility>
using i16=short;
using i64=long long;
using pi=std::pair<int,int>;
const int N=507;const i16 inf=16383;
int n,x,dfn[N],size[N],col[N],ban[N][N];i16 f[N][N][N],t[N][N];std::vector<pi>e[N];
int read(){int x;scanf("%d",&x);return x;}
void dfs1(int u,int f,int r,i64 d)
{
    ban[u][r]=d>x;
    for(auto[v,w]:e[u]) if(v^f) dfs1(v,u,r,d+w);
}
void dfs2(int u,int f)
{
    static int t=0;dfn[u]=++t;
    for(auto[v,w]:e[u]) if(v^f) dfs2(v,u);
}
void dp(int u,int fa)
{
    size[u]=1;f[u][col[u]][dfn[u]]=inf,f[u][!col[u]][dfn[u]]=1;
    for(int i=1;i<=n;++i) if(i^u) if(f[u][1][dfn[i]]=inf,ban[u][i]) f[u][0][dfn[i]]=inf;
    for(auto[v,w]:e[u])
    {
	if(v==fa) continue;
	dp(v,u),memset(t,0x3f,sizeof t);
	for(int j=0;j<=size[v];++j)
	{
	    i16 mn=inf;
	    for(int k=dfn[v];k<dfn[v]+size[v];++k) mn=std::min(mn,f[v][j][k]);
	    for(int i=0;i<=size[u];++i)
		for(int k=1;k<=n;++k)
		{
		    t[i+j][k]=std::min(t[i+j][k],(i16)(f[u][i][k]+f[v][j][k]));
		    if(k<dfn[v]||k>=dfn[v]+size[v]) t[i+j][k]=std::min(t[i+j][k],(i16)(f[u][i][k]+mn));
		}
	}
	size[u]+=size[v],memcpy(f[u],t,sizeof t);
    }
}

int main()
{
    n=read(),x=read();i16 num=0;
    for(int i=1;i<=n;++i) num+=col[i]=read();
    for(int i=1,u,v,w;i<n;++i) u=read(),v=read(),w=read(),e[u].push_back({v,w}),e[v].push_back({u,w});
    for(int i=1;i<=n;++i) dfs1(i,0,i,0);
    dfs2(1,0),dp(1,0);
    for(int i=0;i<=n;++i) for(int j=1;j<=n;++j) if(num>=f[1][i][j]) return !printf("%d",i);
    return puts("-1"),0;
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12652244.html