hackerrank DP Kingdom Division

 树形dp并不擅长,还是步履蹒跚的写出来了,dp[i][j][k],i代表编号为i的点,j为0和1分别代表两种颜色,k为0代表这个点为孤立点,k为1代表这个点为非孤立点。

以一种颜色为例:

1.当这个点为孤立点,它的子节点颜色必定是不同的,若子节点也为孤立点,那么这个子节点永远都不可能变为非孤立点,所以子节点都为颜色相异的非孤立点

2.当这个点为非孤立点,它的子节点至少存在一个点它的颜色和该节点相同,至于是否孤立都不影响,其他子节点只能为颜色不同的非孤立点

第一种情况很好计算,第二种则要需要点思考,至少存在一个。这个是不可能枚举,否则必定超时。举两个数组

a1,a2,a3,a4,a5

b1,b2,b3,b4,b5

(a1+b1)*(a2+b2)*(a3+b3)*(a4+b4)*(a5+b5)=k1+k2+......

可以发现ki为(a1/b1)*(a2/b2)*(a3/b3)*(a4/b4)*(a5/b5)的一个乘积,在减去b1*b2*b3*b4*b5,那么就满足题意了。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<cmath>
#include<set>
#include<stack>
#define ll long long
#define pb push_back
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define cls(name,x) memset(name,x,sizeof(name))
#define pos first
#define index second
#define mp make_pair
using namespace std;
const int inf=1e9+10;
const ll llinf=1e16+10;
const int maxn=1e5+10;
const int maxm=2e5+10;
const int mod=1e9+7;
int n;
ll dp[maxn][2][2];
vector<int> v[maxn];
vector<int> tv[maxn];
int vis[maxn];
void solve(int x)
{
    for(int i=0;i<v[x].size();i++)
    {
        int to=v[x][i];
        solve(to);
    }
    dp[x][0][0]=dp[x][1][0]=1;//孤立点
    dp[x][0][1]=dp[x][1][1]=0;//非孤立点
    for(int i=0;i<v[x].size();i++)
    {
        int to=v[x][i];
        dp[x][1][0]=(dp[x][1][0]*dp[to][0][1])%mod;
        dp[x][0][0]=(dp[x][0][0]*dp[to][1][1])%mod;
    }//若为孤立点,则子节点都为颜色相异的非孤立点
    ll t1=1,t2=1;
    for(int i=0;i<v[x].size();i++)
    {
        int to=v[x][i];
        t1=(t1*(dp[to][1][0]+dp[to][1][1]+dp[to][0][1]))%mod;
    }
    for(int i=0;i<v[x].size();i++)
    {
        int to=v[x][i];
        t2=(t2*dp[to][0][1])%mod;
    }
    dp[x][1][1]=((t1-t2)%mod+mod)%mod;
    //若为非孤立点,则子节点至少存在一个颜色相同的孤立点或者非孤立点,其他子节点必为颜色相异的非孤立点
    t1=1;t2=1;
    for(int i=0;i<v[x].size();i++)
    {
        int to=v[x][i];
        t1=(t1*(dp[to][0][0]+dp[to][0][1]+dp[to][1][1]))%mod;
    }
    for(int i=0;i<v[x].size();i++)
    {
        int to=v[x][i];
        t2=(t2*dp[to][1][1])%mod;
    }
    dp[x][0][1]=((t1-t2)%mod+mod)%mod;
    //若为非孤立点,则子节点至少存在一个颜色相同的孤立点或者非孤立点,其他子节点必为颜色相异的非孤立点
}
void tdfs(int x)
{
    vis[x]=1;
    for(int i=0;i<tv[x].size();i++)
    {
        int to=tv[x][i];
        if(!vis[to])
        {
            v[x].pb(to);
            tdfs(to);
        }
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n-1;i++)
        {
            int a,b;
            scanf("%d %d",&a,&b);
            tv[a].pb(b);
            tv[b].pb(a);
        }
        cls(vis,0);
        tdfs(1);
        solve(1);
        printf("%lld\n",(dp[1][0][1]+dp[1][1][1])%mod);
    }
    return 0;
}

 

posted @ 2017-07-24 18:08  爱种树的码农  阅读(329)  评论(0编辑  收藏  举报