hdu 4842(NOIP 2005 过河)之 动态规划(距离压缩)

/*

hdu 4842(NOIP 2005 过河)之 动态规划(距离压缩)

dp[i] := 到桥上的i位置,最少需要踩到的石子数。

dp[i] = min(dp[i], dp[i-j] + isStone[i])   
	条件:	(1) S<=j<=T
		(2) dp[i-j]是青蛙可以到达的点

独木桥长度L,最大为10^9,直接用转移方程,TLE;由于桥上的石子个数100,所以当石子分布在独木桥上时,是很稀疏的。
(1)S!=T
    考虑,对于此题关键在于求踩到的石子数,而非跳的次数,对于两个相邻石子间的距离、起点与其相邻的最近石子间的距离、
    终点与其相邻的最近石子间的距离都可以进行压缩(整体可看成平移)。
    原因:
		已知青蛙一次跳跃的最小距离S、以及最大距离T,当青蛙所在出发点与目标点的距离>=(T-1)*T时
		(这个具体数值不精确,但是满足想达到的效果,下面有简单的证明),青蛙必然是可以到达目标点的。
		这样,我们便可以利用这个来进行上面提及的距离压缩:将距离>=(T-1)*T的区间缩小(即平移),使青蛙
		不再走那些一定可以到达的非石子点。
(2) S==T
	无法压缩(因为步长固定了),直接判断是否(stone_pos[i] % S == 0),若是,则踩到石子数+1;否则,无须处理。

注意: 计算dp时,需要计算到dp[stone_pos[M + 1] + T - 1]。(因为有可能跳出stone_pos[M + 1])
    stone_pos[M + 1]为距离压缩后,独木桥终点。


------------------------------------------------------------------------------------------
简单证明
注:p可替换为青蛙一次跳跃的距离(T-1),p+1可替换为青蛙一次跳跃的距离(T),x、y即相应的距离跳了多少次。
  Q即为所有跳跃距离加起来的和。

设:x*p + y*(p+1) = Q
则:当Q>=p*(p+1)时,x,y一定有解

证明:(来源于:ACdream群,[BNU]quailty)
	(p+1)*p+0*(p+1)=p(p+1)
	然后x--,y++
			x		y		Q
			(p)	       (1)		p(p+1) + 1
			(p-1)	    (2)		p(p+1) + 2
			......
			(1)	       (p)		p(p+1) + p = p(p+2)

	(p+2)*p+0*(p+1)=p(p+2)
	然后x--,y++
			x		y		Q
			(p+1)	    (1)		p(p+2) + 1
			(p)	        (2)		p(p+2) + 2
			......
			(2)		(p)		p(p+2) + p = p(p+3)
	......
	以此类推,可以到达距离起点>=p*(p+1)的任一点。
	(虽然不严格,但是有助于理解)。
------------------------------------------------------------------------------------------

*/
  1 #include <iostream>
  2 #include <fstream>
  3 #include <sstream>
  4 #include <cstdlib>
  5 #include <cstdio>
  6 #include <cstddef>
  7 #include <iterator>
  8 #include <algorithm>
  9 #include <string>
 10 #include <locale>
 11 #include <cmath>
 12 #include <vector>
 13 #include <cstring>
 14 #include <map>
 15 #include <utility>
 16 #include <queue>
 17 #include <stack>
 18 #include <set>
 19 #include <functional>
 20 using namespace std;
 21 typedef pair<int, int> PII;
 22 typedef long long int64;
 23 const int INF = 0x3f3f3f3f;
 24 const int modPrime = 3046721;
 25 const double eps = 1e-9;
 26 const int MaxN = 11000;
 27 const int MaxM = 110;
 28 const char Opt[4] = { ‘+‘, ‘-‘, ‘*‘, ‘/‘ };
 29
 30 int stone_pos[MaxM];
 31 int dp[MaxN];
 32 int isStone[MaxN];
 33 int L, S, T, M;
 34
 35 int Solve()
 36 {
 37     int rel = 0;
 38     if (S == T)
 39     {
 40         for (int i = 1; i <= M; ++i)
 41         {
 42             if (stone_pos[i] % S == 0)
 43             {
 44                 ++rel;
 45             }
 46         }
 47     }
 48     else
 49     {
 50         int disLen = (T-1)*T;
 51         stone_pos[0] = 0;
 52         stone_pos[M + 1] = L;
 53         sort(stone_pos + 1, stone_pos + M + 1);
 54         int moveLen = 0;
 55         for (int i = 1; i <= (M + 1); ++i)
 56         {
 57             int dis = stone_pos[i] - stone_pos[i - 1] - moveLen;
 58             if (dis > disLen)
 59             {
 60                 moveLen += (dis - disLen);
 61             }
 62             stone_pos[i] -= moveLen;
 63
 64             if (i != (M + 1))
 65             {
 66                 isStone[stone_pos[i]] = 1;
 67             }
 68         }
 69         dp[0] = 0;
 70         for (int i = S; i <= stone_pos[M + 1] + T - 1; ++i)
 71         {
 72             for (int j = i - T; j <= i - S; ++j)
 73             {
 74                 if ((j >= 0) && (-1 != dp[j]))
 75                 {
 76                     if (-1 == dp[i])
 77                     {
 78                         dp[i] = dp[j] + isStone[i];
 79                     }
 80                     else
 81                     {
 82                         dp[i] = min(dp[i], dp[j] + isStone[i]);
 83                     }
 84                 }
 85             }
 86         }
 87
 88         rel = INF;
 89         for (int i = stone_pos[M + 1]; i <= stone_pos[M + 1] + T - 1; ++i)
 90         {
 91             if (-1 != dp[i])
 92             {
 93                 rel = min(rel, dp[i]);
 94             }
 95         }
 96     }
 97     return rel;
 98 }
 99
100 int main()
101 {
102 #ifdef HOME
103     freopen("in", "r", stdin);
104     //freopen("out", "w", stdout);
105 #endif
106
107     int caseNum = 0;
108     while (~scanf("%d", &L))
109     {
110         if (caseNum != 0)
111         {
112             cout << endl;
113         }
114         fill(stone_pos, stone_pos + MaxM, 0);
115         fill(dp, dp + MaxN, -1);
116         fill(isStone, isStone + MaxN, 0);
117         scanf("%d %d %d", &S, &T, &M);
118         for (int i = 1; i <= M; ++i)
119         {
120             scanf("%d", &stone_pos[i]);
121         }
122         int rel = Solve();
123         cout << rel;
124         ++caseNum;
125     }
126
127
128 #ifdef HOME
129     cerr << "Time elapsed: " << clock() / CLOCKS_PER_SEC << " ms" << endl;
130     _CrtDumpMemoryLeaks();
131 #endif
132     return 0;
133 }

 
时间: 2024-10-20 16:09:07

hdu 4842(NOIP 2005 过河)之 动态规划(距离压缩)的相关文章

noip 2005 luogu cogs P1052 过河 WD

111. [NOIP2005] 过河 ★★★   输入文件:river.in   输出文件:river.out   简单对比 时间限制:1 s   内存限制:128 MB [问题描述] 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整 数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点: 0 , 1 ,--, L (其中 L 是桥的长度).坐标为 0 的点表示桥的起点,坐标为 L 的点表示桥

[Luogu 1052] noip 05 过河

[Luogu 1052] noip 05 过河 题目描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度).坐标为0的点表示桥的起点,坐标为L的点表示桥的终点.青蛙从桥的起点开始,不停的向终点方向跳跃.一次跳跃的距离是S到T之间的任意正整数(包括S,T).当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了

HDU 1160 FatMouse&#39;s Speed (动态规划、最长下降子序列)

FatMouse's Speed Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 24573    Accepted Submission(s): 10896Special Judge Problem Description FatMouse believes that the fatter a mouse is, the faster

HDU 1565 方格取数(1) (状态压缩DP)

HDU 1565 方格取数(1) (状态压缩DP) ACM 题目地址: HDU 1565 方格取数(1) 题意: 中文. 分析: dp[i][j]表示前i行状态j的最优解. 先预处理出符合条件的数,17000+个(n在20以内). 不过感觉复杂度挺高的会T,但是却能A. 这题的正解应该是最小割,回头补下. 代码: /* * Author: illuz <iilluzen[at]gmail.com> * File: 1565_dp.cpp * Create Date: 2014-09-19 23

hdu 4771 Stealing Harry Potter&#39;s Precious (状态压缩+bfs)

Stealing Harry Potter's Precious Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1297    Accepted Submission(s): 619 Problem Description Harry Potter has some precious. For example, his invisib

HDU 3341 Lost&#39;s revenge AC自动机+ 状态压缩DP

题意:这个题目和HDU2457有点类似,都是AC自动机上的状态dp,题意就是给你只含有'A','T','C','G',四个字符的子串和文本串,问你文本串如何排列才可以使得文本串中包含有更多的模式串 解题思路:我们知道了 有 num[0] 个 'A', num[1] 个 ‘T’, num[2] 个 ‘C’,num[3] 个‘G’, 我们的可以知道暴力的思路就是把所有的文本串都枚举出来然后一一匹配.我们膜拜了一下春哥以后,就可以有以下思路:  把一个串的信息压缩一下,把具有同样个数字符的串看成是同一

NOIP 2005 青蛙过河

做题记录:2016-08-10 21:58:09 题目描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度).坐标为0的点表示桥的起点,坐标为L的点表示桥的终点.青蛙从桥的起点开始,不停的向终点方向跳跃.一次跳跃的距离是S到T之间的任意正整数(包括S,T).当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出

【NOIP】提高组2005 过河

[算法]状态压缩型DP [题解] Q=tx+(t-1)y 对于Q≥t(t-1),x,y一定有解. 所以当两石子间距离long>t(t-1)时,令long=t(t-1),重新构造数组即可. [注意] 1.输入的石子位置无序,要排序. 2.当s=t时特判. 3.最终解要在n~n+t中找最小值(不过数据太水=v=). #include<cstdio> #include<cstring> #include<algorithm> using namespace std; c

HDU 4311&amp;4312 Meeting point-1&amp;2 (曼哈顿距离&amp;&amp;切比雪夫距离)

HDU 4311 题意:平面上有n个点,一个点(x,y)只能到达(x-1,y), (x+1,y), (x, y-1), (x, y+1)4个点.从n个点中找到一点,使其他点到此点的距离之和最小. 思路: 可以发现,两个点间距离为 |x1-x2| + |y1-y2| ,这便是两点间的曼哈顿距离. 朴素的做法是遍历所有点,枚举该点与其他点间的曼哈顿距离之和,但是会TLE: 取巧的做法是将所有点与中心点的曼哈顿距离排序,枚举中间大概250个点左右的情况比较即可(不要欺负人家数据水! 正确姿势: 用结构