树形DP,除了求出最少需要的次数还需要求出最小次数对应的方案数
dp[u][1]表示u这个点改变为白色,且u这个子树满足条件的最小次数
dp[u][0]表示u这个点不改变且u这棵子树满足条件时的最少次数
转移就是dp[u][1]=
sum(min(dp[vi][1],dp[vi][0]) )+1;
dp[u][0]=sum(dp[vi][1]);
(v是u的全部子节点)
另外再开一个num数组跟着一起转移就可以
注意转移是要用乘法不是加法,每次叶子节点初始化为num[u][0]=num[u][1]=1;
dp[u][1]表示u这个点改变为白色,且u这个子树满足条件的最小次数
dp[u][0]表示u这个点不改变且u这棵子树满足条件时的最少次数
转移就是dp[u][1]=
sum(min(dp[vi][1],dp[vi][0]) )+1;
dp[u][0]=sum(dp[vi][1]);
(v是u的全部子节点)
另外再开一个num数组跟着一起转移就可以
注意转移是要用乘法不是加法,每次叶子节点初始化为num[u][0]=num[u][1]=1;
而且注意最后如果dp[1][0]==dp[1][1].那么ans2=num[1][0]+num[1][1]也要再次取模。这里仍然存在加抄10007的可能性
#include <map>
#include <set>
#include <list>
#include <cmath>
#include<cctype>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b)
{
return a % b == 0 ? b : gcd(b, a % b);
}
#define MAXN 100005
#define MOD 10007
int dp[MAXN][2];
int num[MAXN][2];
int ans1;LL ans2;
vector <int>vv[MAXN];
int N;
void add(int u,int v)
{
vv[u].push_back(v);
}
void init()
{
for (int i=0;i<=N;i++)
vv[i].clear();
}
void dfs(int u,int fa)
{
dp[u][0]=0;dp[u][1]=1;
num[u][0]=1;num[u][1]=1;
for (int i=0;i<vv[u].size();i++)
{
int v=vv[u][i];
if (v==fa) continue;
dfs(v,u);
dp[u][0]+=dp[v][1];
num[u][0]*=num[v][1];
num[u][0]%=10007;
if(dp[v][0]<dp[v][1])
{
dp[u][1]+=dp[v][0];
num[u][1]*=num[v][0];
}
else if(dp[v][0]>dp[v][1])
{
dp[u][1]+=dp[v][1];
num[u][1]*=num[v][1];
}
else
{
dp[u][1]+=dp[v][1];
num[u][1]*=(num[v][0]+num[v][1]);
}
num[u][1]%=10007;
}
}
void slove()
{
scanf("%d",&N);
init();
int x,y;
for (int i=1;i<N;i++)
{
scanf("%d%d",&x,&y);
add(x,y);add(y,x);
}
dfs(1,-1);
ans1=min(dp[1][0],dp[1][1]);
if (dp[1][0]==dp[1][1]) ans2=num[1][0]+num[1][1];
else if (dp[1][0]>dp[1][1]) ans2=num[1][1];
else ans2=num[1][0];
// for (int i=1;i<N;i++) printf("dp[%d][1]=%d ,dp[%d][0]=%d\n",i,dp[i][1],i,dp[i][0]);
// for (int i=1;i<=N;i++) printf("nun[%d][1]=%d ,num[%d][0]=%d\n",i,num[i][1],i,num[i][0]);
printf("%d %lld\n",ans1,ans2%10007);
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
slove();
return 0;
}