• 树形DP-兔子跳跃之谜下


    题目描述

    小生和小森在玩兔子之谜游戏。有三只兔子排成一排。知道每只兔子的初始位置,以及三个兔窝的位置。 

    游戏的规则是,重复以下步骤k次:选择两个不同的兔子AB,分别位于abA可以跳过B到达2*b-a的点: 

     

    跳跃是不允许其他小兔子已经在点2*b-a的位置上: 

     

    跳跃也不允许一次跳过一个以上的兔子: 

     

    现在小生和小森想要知道,k次操作之后,能否让所有兔子都分别跳到一个兔窝里面。注意,第i个兔子并不一定要在第i个巢。并且输出跳法的种数,数值可能很大,要对结果取模1000000007。只要有一个跳跃是不同的,两种方式被认为是不同的。

     

    输入

    有多组测试数据: 
    第一行,包含一个整数Num,表示测试数据的个数。(1<=Num<=10 
    每组测试数据, 
    第一行三个整数,第二行三个整数,分别表示兔子的初始位置和兔窝的位置。两组数值都是严格递增给出。范围均为[-10^18,10^18] 
    最后一个整数k[1,100] 

    输出

    共Num行, 
    跳跃的种数。 

    样例输入

    8

    0 5 8

    0 8 11

    1

    0 5 8

    0 8 11

    3

    0 5 8

    0 8 11

    2

    5 8 58

    13 22 64

    58

    0 1 2

    1 2 3

    100

    5 8 58

    20 26 61

    58

    67 281 2348

    235 1394 3293

    83

    -1000000000000000000 999999999999999998 999999999999999999

    -1000000000000000000 999999999999999999 1000000000000000000

    5

    样例输出

    1

    5

    0

    0

    0

    537851168

    167142023

    29

     

    这道题一拿到不知道怎么做,好像只能DFS

    但是接着我们发现,三只兔子有三种操作:两只兔子跳到中间(一种情况);一只兔子跳到外面(两只兔子跳到外面)。

    可以把兔子间的跳跃抽象成一个二插树形结构

    根节点:三只兔子等距;两只兔子就跳不到中间啦

    叶节点:中间那只兔子分别跳到左边和右边的情况

    对于跳跃的方案数,只是询问在一棵二叉树上两个节点间之间用K步跳跃所能达到的方案数

    我们用dp[i][j][k]表示初始节点ALCA  i步,结束点BLCA  j步,还剩下k步时的方案总数。为了方便处理,我们假设B节点不动(这很重要,也很巧妙)

    当i>0时 让A向上下走dp[i][j][k]+=dp[i-1][j][k-1]+2*dp[i+1][j][k-1]

    当i=0时 让A向上下走(向上走时LCA为A)dp[0][j][k]+=dp[0][j+1][k-1]+dp[0][j-1][k-1]+dp[1][j][k-1]

    当i=j=0时 让A向上下走 dp[0][0][k]=dp[0][1][k-1]+dp[1][0][k-1]*2;

    根据定义,j>B离LCA的距离时DP为0;代码借鉴自LHQ大神的blog

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    #define mod 1000000007
    const int N=107;
    struct note{
        int x,y,z;
        friend bool operator ==(note a,note b)
        {
            return (a.x==b.x&&a.y==b.y&&a.z==b.z);
        }
    }point,point1,fa[2][N];
    int dp[N][N][N];
    int k,deep_a,deep_b;
    bool ok(note s)
    {
        return (!(s.z-s.y==s.y-s.x));
    }
    note make(note s)
    {
        note r;
        if(s.z-s.y<s.y-s.x)
        {
            int kk=s.z-s.y;
            r.x=s.x;
            r.y=s.y-kk;
            r.z=s.y;
            return r;
        }else
        {
            int kk=s.y-s.x;
            r.z=s.z;
            r.x=s.y;
            r.y=s.y+kk;
        }
    }
    int DP(int i,int j,int k)
    {
        if(k==0)
        if(i==0&&j==0) return 1;else return 0;
        if(i+j>k||j>deep_b) return 0;
        if(dp[i][j][k]!=-1) return dp[i][j][k];
        if(i>0&&j>0)
        {
            dp[i][j][k]=(DP(i+1,j,k-1)*2ll+DP(i-1,j,k-1))%mod;  
        }
        else if (i==0&&j>0)  
        {  
            dp[i][j][k]=((ll)DP(1,j,k-1)+DP(0,j-1,k-1)+DP(0,j+1,k-1))%mod;     
        }  
        else if (i>0 && j==0)  
        {  
            dp[i][j][k]=(DP(i+1,0,k-1)*2ll+DP(i-1,0,k-1))%mod;  
        }  
        else if (i==0&&j==0)  
        {  
            dp[i][j][k]=(DP(1,0,k-1)*2ll+DP(0,1,k-1))%mod;  
        }  
        return dp[i][j][k];  
    }
    int main()
    {
        int num;
        scanf("%d",&num);
        while(num--)
        {
            scanf("%lld %lld %lld",&point.x,&point.y,&point.z);
            scanf("%lld %lld %lld",&point1.x,&point1.y,&point1.z);
            scanf("%d",&k);
            fa[0][0]=point;fa[1][0]=point1;
            deep_a=deep_b=0;
            for(int i=1;i<=k&&ok(fa[0][i-1]);i++)
            {
                fa[0][i]=make(fa[0][i-1]);
                deep_a++;    
            }
            for(int i=1;i<=k&&ok(fa[1][i-1]);i++)
            {
                fa[1][i]=make(fa[1][i-1]);
                deep_b++;
            }
            bool flag=1;
            int t1=-1,t2=-1;
            for(int i=0;i<=deep_a&&flag;i++)
                for(int j=0;j<=deep_b&&flag;j++)
                {
                    if(fa[0][i]==fa[1][j])
                    {
                        t1=i,t2=j;
                        flag=false;
                    }
                }
            if(t1==-1)
            {
                cout<<0<<endl;
                continue;    
            }    
            dp[0][0][0]=1;
            memset(dp,-1,sizeof(dp));
            printf("%d
    ",DP(t1,t2,k));
        }
        return 0;    
    }

     

  • 相关阅读:
    Java Singleton 单例模式
    android 让真机显示 DeBug Log调试信息
    android 图片处理经验分享
    android GridView 的使用 实现多项选择
    Spark/Storm/Flink
    Https
    Netty
    Netty
    java 线程状态相关测试
    Socket buffer 调优相关
  • 原文地址:https://www.cnblogs.com/dancer16/p/6984352.html
Copyright © 2020-2023  润新知