【洛谷】P1052 过河【DP+路径压缩】
题目描述
在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,…,L(其中L是桥的长度)。坐标为0的点表示桥的起点,坐标为L的点表示桥的终点。青蛙从桥的起点开始,不停的向终点方向跳跃。一次跳跃的距离是S到T之间的任意正整数(包括S,T)。当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥。
题目给出独木桥的长度L,青蛙跳跃的距离范围S,T,桥上石子的位置。你的任务是确定青蛙要想过河,最少需要踩到的石子数。
输入输出格式
输入格式:
第一行有1个正整数L(1≤L≤109),表示独木桥的长度。
第二行有3个正整数S,T,M,分别表示青蛙一次跳跃的最小距离,最大距离及桥上石子的个数,其中1≤S≤T≤10,1≤M≤100。
第三行有M个不同的正整数分别表示这M个石子在数轴上的位置(数据保证桥的起点和终点处没有石子)。所有相邻的整数之间用一个空格隔开。
输出格式:
一个整数,表示青蛙过河最少需要踩到的石子数。
输入输出样例
说明
对于30%的数据,L≤10000;
对于全部的数据,L≤109。
2005提高组第二题
一开始被题目坑惨了啊...看到题就打了个建边$Spfa$,然后样例怎么过不了???
仔细研读样例发现是在可以不踩石头的情况下最少要踩几个石头啊!!!
然后重新定义dp方程...发现$S$和$T$是小于等于10的,$L$又莽大。所以考虑如何把空间压下去。考虑路径压缩。
以下贴的洛谷大佬Panda_hu的题解:
当然,我觉得还是直接$mod$2520比较好理解...因为在10范围内,不论怎么跳,都可以跳到2520,所以只要两个石头距离大于2520的时候,直接$mod$2520。
路径压缩了过后扫一遍更新即可,如果当前有石头就必须踩。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cstring> using namespace std; int L, S, T, M, f[3000005], flag[3000005], d[105]; struct Node { int pos; } Stone[105]; bool cmp ( Node a, Node b ) { return a.pos < b.pos; } int main ( ) { scanf ( "%d", &L ); scanf ( "%d%d%d", &S, &T, &M ); for ( int i = 1; i <= M; i ++ ) scanf ( "%d", &Stone[i].pos ); sort ( Stone + 1, Stone + 1 + M, cmp ); for ( int i = 1; i <= M; i ++ ) d[i] = ( Stone[i].pos - Stone[i-1].pos ) % 2520; for ( int i = 1; i <= M; i ++ ) { Stone[i].pos = Stone[i-1].pos + d[i]; flag[Stone[i].pos] = 1; } memset ( f, 0x3f3f3f3f, sizeof ( f ) ); f[0] = 0; for ( int i = 1; i <= Stone[M].pos + T; i ++ ) { for ( int j = S; j <= T; j ++ ) if ( i - j >= 0 ) f[i] = min ( f[i-j], f[i] ); f[i] += flag[i]; } int ans = 0x3f3f3f3f; for ( int i = Stone[M].pos; i < Stone[M].pos + T; i ++ ) ans = min ( ans, f[i] ); printf ( "%d", ans ); return 0; }