CF375E Red and Black Tree

cf

這裏的交換顏色其實就是選擇相等數量的黑點和紅點翻轉顏色,並且可以發現交換後黑點總數\(cnt\)是不變的.所以可以從\(cnt\)不變入手,我們在樹上選出\(cnt\)個黑點,其中如果有紅點就翻轉顏色(假設這裏紅點數量爲\(num\)),如果有些黑點沒被選中就任選其中\(num\)個翻轉成紅點,這與原問題是等價的.現在我們只要最小化\(num\)使得樹滿足條件.

考慮dp,設\(f_{x,j,k}\)表示在\(x\)子樹內選中\(j\)個黑點,能夠覆蓋\(x\)條件的黑點爲\(k\)子樹內最小\(num\)(\(k\)可以在子樹外,這裏規定\(k\)翻轉產生的代價在\(k\)處算,即初始化時\(f_{x,j,k}=[col_x=0\&\&x\ne k]\)).轉移類似樹形揹包,每次合併兩個狀態\(f_{x,j,k},f_{y,p,q}\)

  • \(k=q\),那麼有\(f_{x,j,k}+f_{y,p,k}\to f'_{x,j+p,k}\)

  • \(k\ne q\),且\(q\)\(y\)子樹內,那麼有\(f_{x,j,k}+\min_{q\in subtree(y)}f_{y,p,q}\to f'_{x,j+p,k}\).注意這時要保證\(k\notin subtree(y)\),因爲\(k\)的選擇和翻轉產生的代價是在\(k\)處算的,不這樣規定就會少算代價

  • \(k\ne q\),且\(q\)\(y\)子樹外,這時只要選擇\(k,q\)其中的一個即可,即這種情況一定不優,所以不用考慮

#include<bits/stdc++.h>
#define LL long long
#define db long double

using namespace std;
const int N=500+5,inf=1e9+7;
int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
    return x*w;
}
int to[N<<1],nt[N<<1],w[N<<1],hd[N],tot=1;
void adde(int x,int y,int z)
{
    ++tot,to[tot]=y,nt[tot]=hd[x],w[tot]=z,hd[x]=tot;
    ++tot,to[tot]=x,nt[tot]=hd[y],w[tot]=z,hd[y]=tot;
}
short f[N][N][N],g[N][N],fa[N],dfn[N],ti,sz[N];
int di[N][N],n,lm;
bool co[N];
void dd1(int x,int ffa,int xx,int nd)
{
    di[x][xx]=nd;
    for(int i=hd[x];i;i=nt[i])
    {
    	int y=to[i];
    	if(y==ffa) continue;
    	dd1(y,x,xx,min((int)(nd+w[i]),inf));
    }
}
void dd2(int x)
{
    dfn[x]=++ti;
    for(int i=hd[x];i;i=nt[i])
    {
    	int y=to[i];
    	if(y==fa[x]) continue;
    	fa[y]=x,dd2(y);
    }
}
void dfs(int x)
{
    sz[x]=1;
    for(int z=1;z<=n;++z) if(z!=x&&di[z][x]<=lm) f[x][0][dfn[z]]=0;
    f[x][1][dfn[x]]=!co[x];
    for(int i=hd[x];i;i=nt[i])
    {
    	int y=to[i];
    	if(y==fa[x]) continue;
    	dfs(y);
    	for(int j=0;j<=sz[x]+sz[y];++j)
    	    memset(g[j],0x3f3f3f,sizeof(short)*(n+1));
    	for(int j=0;j<=sz[x];++j)
    	    for(int k=0;k<=sz[y];++k)
    	    {
        	short nv=1<<13;
        	for(int v=dfn[y];v<dfn[y]+sz[y];++v) nv=min(nv,f[y][k][v]);
        	for(int u=1;u<=n;++u)
      		{
       		    g[j+k][u]=min(g[j+k][u],(short)(f[x][j][u]+f[y][k][u]));
       		    if(u<dfn[y]||u>=dfn[y]+sz[y]) g[j+k][u]=min(g[j+k][u],(short)(f[x][j][u]+nv));
       		}
    	    }
    	for(int j=0;j<=sz[x]+sz[y];++j)
    	    memcpy(f[x][j],g[j],sizeof(short)*(n+1));
    	sz[x]+=sz[y];
    }
}

int main()
{
    n=rd(),lm=rd();
    int cn=0;
    for(int i=1;i<=n;++i) cn+=co[i]=rd();
    for(int i=1;i<n;++i)
    {
    	int x=rd(),y=rd(),z=rd();
	    adde(x,y,z);
    }
    for(int i=1;i<=n;++i) dd1(i,0,i,0);
    dd2(1);
    memset(f,0x3f3f3f,sizeof(f));
    dfs(1);
    short ans=1<<13;
    for(int i=1;i<=n;++i) ans=min(ans,f[1][cn][i]);
    cout<<(ans<=n?ans:-1);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章