这一周训练了dp
One day, little Vasya found himself in a maze consisting of (n + 1) rooms, numbered from 1 to (n + 1). Initially, Vasya is at the first room and to get out of the maze, he needs to get to the (n + 1)-th one.
The maze is organized as follows. Each room of the maze has two one-way portals. Let’s consider room number i (1 ≤ i ≤ n), someone can use the first portal to move from it to room number (i + 1), also someone can use the second portal to move from it to room number pi, where 1 ≤ pi ≤ i.
In order not to get lost, Vasya decided to act as follows.
Each time Vasya enters some room, he paints a cross on its ceiling. Initially, Vasya paints a cross at the ceiling of room 1.
Let’s assume that Vasya is in room i and has already painted a cross on its ceiling. Then, if the ceiling now contains an odd number of crosses, Vasya uses the second portal (it leads to room pi), otherwise Vasya uses the first portal.
Help Vasya determine the number of times he needs to use portals to get to room (n + 1) in the end.
Input
The first line contains integer n (1 ≤ n ≤ 103) — the number of rooms. The second line contains n integers pi (1 ≤ pi ≤ i). Each pi denotes the number of the room, that someone can reach, if he will use the second portal in the i-th room.
Output
Print a single number — the number of portal moves the boy needs to go out of the maze. As the number can be rather large, print it modulo 1000000007 (109 + 7).
题目大意:
有n间房子起初v在第一间且每到一个房子v画一个记号,记号是偶数时他可以进入下一个房间,奇数时被传送到指定的房间p,(1<=p<=i);最终到达n+1房间时进入房间的次数。
这个题按照题目要求来看就只有题目说的一条解决方案,因为进门次数超过10e9这只能是找规律的题。
求解:
因为只有偶数时才能进入下一个房间,对于每一个房间,dp[i]+2时才能进入下一个房间,假设传送进的房间都为第一个房间,便相当于重新走一遍,dp[i]=(dp[i]+dp[i-1]*2+2-dp[0]),所以进入p房间dp[i]=(dp[i]+dp[i-1]*2+2-dp[p]),题目求模时要注意dp[i]取模后可能小于(dp[p]+1)所以在括号中加入模,dp[i]=(dp[i]+dp[i-1]*2+2-dp[0]+N)%N
源代码
#include<iostream>
#define N 1000000007
using namespace std;
long long ss[10000],dp[10000];
int main()
{
int n;
cin >> n;
for(int i=1;i<=n;i++)
scanf("%lld",&ss[i]);
for(int i=1;i<=n;i++)
{dp[i]=(2*dp[i-1]-dp[ss[i]-1]+2+N)%N;}
printf("%lld",dp[n]);
}
这是一个简单的生存游戏,你控制一个机器人从一个棋盘的起始点(1,1)走到棋盘的终点(n,m)。游戏的规则描述如下:
1.机器人一开始在棋盘的起始点并有起始点所标有的能量。
2.机器人只能向右或者向下走,并且每走一步消耗一单位能量。
3.机器人不能在原地停留。
4.当机器人选择了一条可行路径后,当他走到这条路径的终点时,他将只有终点所标记的能量。
如上图,机器人一开始在(1,1)点,并拥有4单位能量,蓝色方块表示他所能到达的点,如果他在这次路径选择中选择的终点是(2,4)
点,当他到达(2,4)点时将拥有1单位的能量,并开始下一次路径选择,直到到达(6,6)点。
我们的问题是机器人有多少种方式从起点走到终点。这可能是一个很大的数,输出的结果对10000取模。
Input
第一行输入一个整数T,表示数据的组数。
对于每一组数据第一行输入两个整数n,m(1 <= n,m <= 100)。表示棋盘的大小。接下来输入n行,每行m个整数e(0 <= e < 20)。
Output
对于每一组数据输出方式总数对10000取模的结果.
题目大意:
小机器人初始有四单位能量,它每次只能向右或向下走一格且耗费一单位能量。在耗尽能量前,它可以将它走到的任意一点是为他的中继点,并且继承目的地标识的能量(并不叠加),然后继续这样,直到到达(n,n)点。
思路:题目规则显然是每一次dp[i][j]=(dp[i1][j1]+dp[i2][j2]+…dp[in][jn])(ia+ib-i-j<=e)(1<=a<=n)一对多可以用搜索算法。
源代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int dp[1005][1005];
int loc[2000][2000];
int m,n;
int dfs(int x,int y)
{
int e=loc[x][y];
int sum=x+y;
if(dp[x][y]!=-1)
return dp[x][y];
dp[x][y]=0;
for(int i=x;i<=x+e;i++)
for(int o=y;o<=y+e;o++)
{
if((i+o-sum)&&i+o-sum<=e&&i<=m&&o<=n)
{dp[x][y]=(dp[x][y]+dfs(i,o))%10000;}
}
return dp[x][y];
}
int main()
{
int nl;
cin>>nl;
while(nl--)
{
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++)
for(int o=1;o<=n;o++)
scanf("%d",&loc[i][o]);
memset(dp,-1,sizeof(dp));
dp[m][n]=1;
cout<<dfs(1,1)<<endl;
memset(dp,0,sizeof(dp));
}
}