题意:给你一棵树,有三种节点,0,1,-1。权值为-1的节点可以变为0或者1,若一条边的两个节点的权值不同,则ans++,求最小ans。
题解:树形dp,定义dp[i][j]表示节点i是0或者1的最小ans,对于当前节点,若是-1则dp[i][0]=dp[i][1]=0,否则dp[i][a[i]]=0,dp[i][a[i]^1]=1。
转移为:
dp[u][0]+=min(dp[to][0],dp[to][1]+1);//to是子节点
dp[u][1]+=min(dp[to][1],dp[to][0]+1);
AC代码:
#include<stdio.h>
#include<vector>
#define inf 1000000000
using namespace std;
int a[100005];
vector<int>vt[100005];
int dp[100005][2];
void dfs(int u,int fa)
{
if(a[u]!=-1)dp[u][a[u]]=0,dp[u][a[u]^1]=inf;
else dp[u][0]=dp[u][1]=0;
for(int i=0;i<vt[u].size();i++)
{
int to=vt[u][i];
if(to==fa)continue;
dfs(to,u);
dp[u][0]+=min(dp[to][0],dp[to][1]+1);
dp[u][1]+=min(dp[to][1],dp[to][0]+1);
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),vt[i].clear();
for(int i=0;i<n-1;i++)
{
int u,v;
scanf("%d%d",&u,&v);
vt[u].push_back(v);
vt[v].push_back(u);
}
dfs(1,-1);
if(a[1]==-1)printf("%d\n",min(dp[1][0],dp[1][1]));
else printf("%d\n",dp[1][a[1]]);
}
}