博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
树形DP-兔子跳跃之谜下
阅读量:5738 次
发布时间:2019-06-18

本文共 3113 字,大约阅读时间需要 10 分钟。

题目描述

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

游戏的规则是,重复以下步骤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
#include
#include
#include
using namespace std;typedef long long ll;#define mod 1000000007const 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
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<

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/dancer16/p/6984352.html

你可能感兴趣的文章
fopen打开文件失败的问题
查看>>
jQuery|元素遍历
查看>>
sql语句大全
查看>>
RedHat 6 安装配置Apache 2.2
查看>>
Openstack 安装部署指南翻译系列 之 Manila服务安装(Share Storage)
查看>>
underscore.js学习笔记
查看>>
Centos7安装
查看>>
windows下常用命令
查看>>
1.5编程基础之循环控制_29:数字反转
查看>>
iptables的CLUSTER target与以太网交换机的思想
查看>>
Vsftpd的安全性
查看>>
组策略 之 设备安装设置
查看>>
人工智能还能干这些?这8种AI应用你可能意想不到
查看>>
实现Hyper-V 虚拟机在不同架构的处理器间迁移
查看>>
linux根目录下的文件解析
查看>>
简单使用saltstack
查看>>
针对web服务器容灾自动切换方案
查看>>
LTE学习笔记(一)——背景知识
查看>>
突破媒体转码效率壁垒 阿里云首推倍速转码
查看>>
容器存储中那些潜在的挑战和机遇
查看>>