存在n+1个房间,每个房间依次为房间1 2 3…i,每个房间都存在一个传送门,i房间的传送门可以把人传送到房间pi(1<=pi<=i),现在路人甲从房间1开始出发(当前房间1即第一次访问),每次移动他有两种移动策略:
A. 如果访问过当前房间 i 偶数次,那么下一次移动到房间i+1;
B. 如果访问过当前房间 i 奇数次,那么移动到房间pi;
现在路人甲想知道移动到房间n+1一共需要多少次移动;
输入描述:
第一行包括一个数字n(30%数据1<=n<=100,100%数据 1<=n<=1000),表示房间的数量,接下来一行存在n个数字 pi(1<=pi<=i), pi表示从房间i可以传送到房间pi。
输出描述:
输出一行数字,表示最终移动的次数,最终结果需要对1000000007 (10e9 + 7) 取模。
思路:这道题对于我来说算是一个非常抽象的题目,我也是想了两天突然想通了,我试着给大家讲清楚。。。
我们定义一个dp[n+2]的数组,代表跳到当前房子次数为奇数次的步数,因为房子从1开始,一共有n+1个房子,所以数组长度定为n+2;在定义一个p[n+1]数组,代表执行A策略的时候,可以跳到的房子位置。
1、现在第一次跳到i-1房子的次数为奇数次那么之前的i-2个房子都已经跳了偶数次,不然不可能到i-1房子这里,此时执行B策略,跳到p[i-1],这过程中步数+1;
2、此时跳到p[i-1],他肯定是奇数次了,其他的门都是偶数次,那么这和第一次跳到p[i-1]房子的情况完全相同,那么再从p[i-1]房子跳到i-1房子的步数为dp[i-1]-dp[p[i-1]];
3、此时是第二次跳到i-1房子已经是偶数次了,此时执行A策略,向前跳一个房子,此时步数+1;
那么我们就得到了状态方程:dp[i] = dp[i-1]+1+dp[i-1]-dp[p[i-1]]+1;
代码如下:
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
long mod = 1000000007;
int[] p = new int[n+1];
long[] dp = new long[n+2];
//表示当前跳到当前房子的奇数次
for(int i=1;i<=n;i++){
p[i] = sc.nextInt();
}
for(int i=2;i<n+2;i++){
dp[i] = dp[i-1]+1+dp[i-1]-dp[p[i-1]]+1;
dp[i] = dp[i]%mod;
}
System.out.println(dp[n+1]<0?dp[n+1]+mod:dp[n+1]);
}
}
虽然代码很短,但是我觉得真的很难理解,害。