Gym102460B The Power Monitor System(树形dp)

当不存在没有被染色的边时: 若被自己染黑,则由于规则 1,这个点染了以后所有儿子都会被染 色,因此儿子的情况可以随便选:

fu,1,0 = 1 + ∑min{fv,0/1/2,0/1}

若被儿子染黑,则必须要选择一个儿子传递上去,儿子能传递上 来只有两种情况: fu,0,0 = minv{min{fv,0,0, fv,1,0} + ∑ v ′̸=v min{fv,0,0, fv,0,1, fv,1,0}}

若只被父亲染黑,则儿子不能把 u 染黑,为了 u 和儿子之间的边 能够被覆盖,只能用规则 2,发现只有一种情况:fu,2,0 = ∑fv,0,1

当与儿子的边中存在一条没有被染色时: 若被儿子染黑,那么要在上面的 fu,0,0 中转移式的 v ′ 中再抽出一 个 v ′′,这个 v ′′ 的贡献只能是 min{fv ′′ ,2,0/1}

若只被父亲染黑,同理,在上面的 fu,2,0 中转移式的 v 中抽出一个 v ′,这个 v ′ 的贡献也只能是 min{fv ′ ,2,0/1}

时间复杂度 O(n)。

存在一条没有被染色的提取出来的代价的意义是,我们定义的状态f[u][2][1]是u与儿子在一条边没被染色,这条边因为规则4,其他边都被染色的情况下染色的状态,因此我们需要提取出这个信息。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4e5+10;
const int inf=0x3f3f3f3f;
ll f[N][3][3];
int h[N],ne[N],e[N],idx;
int in[N];
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int fa){
    f[u][1][0]=1,f[u][2][0]=0;
    if(in[u]==1&&fa!=-1)
        return ;
    f[u][0][0]=f[u][0][1]=f[u][2][0]=f[u][2][1]=0;
    ll g[2]={0,inf};
    ll tmp[2][2]={0,inf,inf,inf};
    for(int i=h[u];i!=-1;i=ne[i]){
        int v=e[i];
        if(v==fa)
            continue;
        dfs(v,u);
        ll tmp1=min(f[v][1][0],min(f[v][0][1],f[v][0][0]));
        g[1]=min(g[1]+tmp1,g[0]+min(f[v][1][0],f[v][0][0]));
        g[0]+=tmp1;
        tmp[1][1]=min(tmp[1][1]+tmp1,min(tmp[0][1]+min(f[v][1][0],f[v][0][0]),tmp[1][0]+min(f[v][2][1],f[v][2][0])));
        tmp[1][0]=min(tmp[1][0]+tmp1,tmp[0][0]+min(f[v][1][0],f[v][0][0]));
        tmp[0][1]=min(tmp[0][1]+tmp1,tmp[0][0]+min(f[v][2][1],f[v][2][0]));
        tmp[0][0]+=tmp1;
        f[u][1][0]+=min(f[v][1][0],min(f[v][0][0],min(f[v][0][1],min(f[v][2][0],f[v][2][1]))));
        f[u][2][1]=min(f[u][2][0]+min(f[v][2][1],f[v][2][0]),f[u][2][1]+f[v][0][1]);
        f[u][2][0]+=f[v][0][1];
    }
    f[u][0][0]=g[1];
    f[u][0][1]=tmp[1][1];
}
int main(){
    ios::sync_with_stdio(false);
    memset(h,-1,sizeof h);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        for(int j=0;j<3;j++){
            for(int k=0;k<2;k++)
                f[i][j][k]=0x3f3f3f3f;
        }
    }
    for(int i=1;i<n;i++){
        int a,b;
        cin>>a>>b;
        add(a,b);
        add(b,a);
        in[a]++;
        in[b]++;
    }
    dfs(1,-1);
    cout<<min(f[1][1][0],min(f[1][0][0],f[1][0][1]))<<endl;
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/13780765.html