zoj-4007(树形dp)

通过模拟可以得到一个dp公式:

如果为0的话转移方程为:dp[0][u] += min(dp[1][v]+1,dp[0][v]),

如果为1的话转移方程为:dp[1][u] += min(dp[1][v],dp[0][v]+1),

如果为-1的话转移方程为:dp[0][u] += min(dp[1][v]+1,dp[0][v]);

                                           dp[1][u] += min(dp[1][v],dp[0][v]+1);

最后的答案就是min(dp[1][1],dp[0][1]),建议自己模拟一下dp过程;

代码如下:

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
const int mx = 1e5+5;
const int inf = 1e6;
int n,m;
vector<int>g[mx];
int a[mx];
int dp[2][mx];
void dfs(int u,int fa)
{
    if(a[u]==-1)
        dp[0][u] = dp[1][u] = 0; 
    else
        dp[a[u]][u] = 0;/*将符合题意的初始状态定为0*/
    for(int i=0;i<g[u].size();i++)/*把与该点连接的点扫一次*/
    {
        int v=g[u][i];
        if(v!=fa)/*要求不能是父节点*/
        {
            dfs(v,u);
            if(a[u]==-1)
            {
                dp[0][u] += min(dp[0][v],dp[1][v]+1);
                dp[1][u] += min(dp[0][v]+1,dp[1][v]);
            }
            else
                dp[a[u]][u] += min(dp[a[u]][v],dp[a[u]^1][v]+1);
        }
    }
}
int main()
{
    int t,q,ca = 1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i = 1; i <= n; i++)
        {
            scanf("%d",&a[i]);
            dp[0][i] = dp[1][i] = inf;
            g[i].clear();
        }
        for(int i = 1; i < n; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            g[u].push_back(v);
            g[v].push_back(u);/*将与该节点连接的点储存起来*/
        }
        dfs(1,1);/*从根节点开始dp*/
        printf("%d\n",min(dp[0][1],dp[1][1]));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/KasenBob/p/10043441.html