2014 UESTC Training for Dynamic Programming L

来源:互联网 发布:成都电子科技大学 知乎 编辑:程序博客网 时间:2024/05/22 15:15
树形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[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.1415926535897932626using namespace std;int gcd(int a, int b){return a % b == 0 ? b : gcd(b, a % b);}#define MAXN 100005#define MOD 10007int 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;}


0 0
原创粉丝点击