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 }

 

 
posted @ 2016-01-21 20:51  JmingS  阅读(662)  评论(0编辑  收藏  举报