1052 过河
难度:提高+/省选-
题目类型:动态规划
提交次数:2
涉及知识:多维动规
题目描述
在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度)。坐标为0的点表示桥的起点,坐标为L的点表示桥的终点。青蛙从桥的起点开始,不停的向终点方向跳跃。一次跳跃的距离是S到T之间的任意正整数(包括S,T)。当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥。
题目给出独木桥的长度L,青蛙跳跃的距离范围S,T,桥上石子的位置。你的任务是确定青蛙要想过河,最少需要踩到的石子数。
输入输出格式
输入格式:
输入文件river.in的第一行有一个正整数L(1 <= L <= 10^9),表示独木桥的长度。第二行有三个正整数S,T,M,分别表示青蛙一次跳跃的最小距离,最大距离,及桥上石子的个数,其中1 <= S <= T <= 10,1 <= M <= 100。第三行有M个不同的正整数分别表示这M个石子在数轴上的位置(数据保证桥的起点和终点处没有石子)。所有相邻的整数之间用一个空格隔开。
输出格式:
输出文件river.out只包括一个整数,表示青蛙过河最少需要踩到的石子数。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 int stone[100]; 6 int st[10005]; 7 int d[10005]; 8 int f[10005]; 9 const int inf = 1<<30; 10 int l, s, t, m; 11 int ans; 12 int main(){ 13 cin>>l>>s>>t>>m; 14 int i, j, k; 15 for(i = 1; i <= m; i++) 16 cin>>stone[i]; 17 sort(stone+1, stone+m+1); 18 for(i = 1; i <= m; i++){ 19 d[i] = stone[i]-stone[i-1]; 20 if(d[i]>90) d[i] = 90; 21 } 22 23 /*当只能跳跃一种距离时*/ 24 if(s==t){ 25 for(i = 1; i <= m; i++) 26 if(stone[i]%s==0) ans++; 27 cout<<ans<<endl; 28 return 0; 29 } 30 31 /*当跳跃范围为s~t时*/ 32 //路径压缩 st[i]表示坐标i处是否有石头 33 for(i = 1; i <= m; i++){ 34 stone[i] = stone[i-1]+d[i]; 35 st[stone[i]] = 1; 36 } 37 l = stone[m]+t; 38 39 for(i = 1; i <= l; i++) 40 f[i] = inf; 41 42 f[s] = st[s]; 43 for(i = s; i <= l; i++){ 44 for(j = s; j <= t; j++){ 45 f[i] = min(f[i], f[i-j]+st[i]); 46 } 47 } 48 cout<<f[l]; 49 return 0; 50 }
备注:
我现在整个人都非常不好。这道题已经耗了我足足三个小时。
先用一个小时看路径压缩为什么可以的证明。
摘录题解如下:
命题:对于步幅s到t若目标位置距起始点距离D≥s(s-1)则一定可以到达目标点
证明:
设一次可以走p步或p+1步
方便起见,我们取起始位置为坐标0点
那么p(p-1)点一定可以达到(每次走p的距离,走p-1次)
因为我们也可以每次走p+1步
所以可以通过将一次p距离的行走替换为p+1距离的行走来实现总距离+1。
http://blog.csdn.net/liuhuiyi/article/details/8202453 这个链接用扩展欧几里得证的,讲得挺清楚。
然后我就开始尝试独立写代码了。
凡是间隔大于90的全压成90。注意s==t时要单独讨论,注意初始化为inf。。
其他的关于填表的问题,我被逼的没办法了,就直接照题解改的。但我现在实在不想再想第二遍了。等心情好的时候再思考。。。