大富翁
dafuweng.pas/c/cpp
1S/256MB
【题目描述】
想必大家都玩过大富翁的游戏,现在我们把它简单化:现在有N个格子排成一行,最左到右编号为1到N。玩家初始在1号格子,每一轮玩家掷一枚骰子,掷出的点数为1~6,然后玩家向右移动与掷出的点数相同的步数。例如玩家当前站在3号格子上,玩家掷出点数为5,则他会走到8号格子上。现在某些格子上有传送门,我们用(ai, bi)来表示第i个传送门,当玩家恰好停在编号为ai的格子时,会被自动传送到编号为bi的格子。
不过现在玩家有很多个叫做“遥控骰子”的道具,每次使用“遥控骰子”后,玩家都能控制本回合骰子的点数,因为玩家拥有的“遥控骰子”相当多,所以我们可以认为玩家可以始终遥控骰子的点数。
现在的问题是:告诉你这些传送门的位置,你能求出玩家从1号格子到达N号格子最少需要投多少轮骰子吗?
【输入】
输入文件:dafuweng.in
输入的第一行包含两个整数N,M,分别表示格子的数目和传送门的数目。
接下来M行,每行包含两个数ai, bi。分别表示第i号传送门的起点和终点。
【输出】
输入文件:dafuweng.out
输出为一行,包含一个整数,表示玩家从1号格子到达N号格子所需要的最少轮数。
【输入样例】
100 4
7 14
13 30
35 50
40 99
【输出样例】
6
【数据范围】
对于100%的数据,2<=N<=100000,0<=M<=100
对于100%的数据,1<ai<bi<=N,且所有的ai均不相同。
这一题和下棋类似,不过多了一个传送门
我们先看看下棋的转移方程f[i]=max{f[i-1],f[i-2],…,f[i-5],f[i-6]}+1;
那么这里有了传送门,我们的状态就多了一种f[i]=f[t];
注意一点,如果有一个传送门是7-->12,那么我们推f[12]的时候从第一个方程会得到f[12]=max{…,f[7],…}+1; 但是事实上我们是不能从7掷骰子过来的(到了7就会自动传送到12!)所以我们还需要判断一下
我的存储方法是用hx[x]=y表示从x要传送到y,用h[y]=x表示y是由x传送而来的
值得注意的是题目最后说了一句所有的ai均不相同,但是没有说bi不同!!!
所以h[]数组的下标就会重复,以至于覆盖以前的值,可行的修改方法是写成链表,当然了,由于门最多只有100个,所以我们在数组后面多开一维,写成一个伪链表就ok了!
所以存储时小心一些就行了(我就没注意那句话!!!WA了两组)
C++ Code
/*
C++ Code
http://blog.csdn.net/jiangzh7
By Jiangzh
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=100000+10;
int n,m;
int h[MAXN][110],hx[MAXN];
int l[MAXN];
int f[MAXN];
void read()
{
freopen("dafuweng.in","r",stdin);
freopen("dafuweng.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
h[y][l[y]++]=x;//表示 y 是从 x 传送而来的
hx[x]=y;//表示从 x 可以传送到 y
}
}
void work()
{
memset(f,0x3f,sizeof(f));
f[1]=0;
for(int i=1;i<=n;i++)
{
if(h[i][0])
for(int j=0;j<l[i];j++) f[i]=min(f[i],f[h[i][j]]);
for(int j=1;j<=6;j++)
{
if(i-j<1) continue;//越界
if(hx[i-j]) continue;//位置i-j是会传送的 不能掷骰子
f[i]=min(f[i],f[i-j]+1);
}
}
printf("%d",f[n]);
}
int main()
{
read();
work();
return 0;
}