1119. Metro(动态规划,滚动数组)
2013-06-19 19:26
330 查看
题意:
输入首行为N,M (0 < N,M <= 1000)表示东西、南北的格子数,每格100米。Nikanor从格子(1,1)的西南角的家出发,地铁站位于格子(N,M)的东北角。第二行为K(0 <= K <= 100),表示有k个格子允许对角线穿越。以下K行为允许对角线穿越的格子,分别用一对数表示,空格隔开。
求Nikanor的家到地铁站的最短路径,四舍五入到整数米。
用动态规划:
设f[i][j]是出发点到点a[i][j]的最短路径
f[i][j] = min(f[i-1][j], f[i][j-1]) + 100 //不能从a[i-1][j-1]到a[i][j]
f[i][j] = min(f[i-1][j]+100, f[i][j-1]+100, f[i-1][j-1] + 100√2) //能从a[i-1][j-1]到a[i][j]
但是由于内存限制,用二维数组dp会超内存,由于f[i][j]只赖于f[i-1][j],f[i][j-1],可以用滚动数组。
一个DP,平常如果需要1000×1000的空间,其实根据DP的无后效性,可以开成2×1000,然后通过滚动,获得和1000×1000一样的效果。滚动数组常用于DP之中,在DP过程中,我们在由一个状态转向另一个状态时,很可能之前存储的某些状态信息就已经无用了,例如在01背包问题中,从理解角度讲我们应开DP[i][j]的二维数组,第一维我们存处理到第几个物品,也就是阶段了,第二维存储容量,但是我们获得DP[i],只需使用DP[i - 1]的信息,DP[i - k],k>1都成了无用空间,因此我们可以将数组开成一维就行,迭代更新数组中内容,滚动数组也是这个原理,目的也一样,不过这时候的问题常常是不可能缩成一维的了,比如一个DP[i][j]需要由DP[i - 1 ][k],DP[i - 2][k]决定,i<n,0<k<=10;n <= 100000000;显然缩不成一维,正常我们应该开一个DP[100000005][11]的数组,结果很明显,超内存,其实我们只要开DP[3][11]就够了DP[i%3][j]由DP[(i - 1)%3][k]和DP[(i - 2)%3][k]决定,空间复杂度差别巨大。
另外在讨论贴看到了另一种更好的解法:算法2:
可以发现,如果我们只走直边的话,要走(N+M)*100长度。如果走C条斜边,那么要走(C*141.4213562373)+(N+M-C*2)*100 的长度。那么显然我们要尽可能使C更大,即多走斜边。
这样可以转化为经典的LIS模型。即把所有的斜边按照坐标排序,然后求最长的上升序列(x,y都要严格递增),走这样的斜边一定是最优的策略。于是我们可以求出C。
结果就是(C*141.4213562373)+(N+M-C*2)*100。
Vijos 1336其实就是这道题的数据加大版。对于较小的K和很大的N,M,只能用算法2解决。
输入首行为N,M (0 < N,M <= 1000)表示东西、南北的格子数,每格100米。Nikanor从格子(1,1)的西南角的家出发,地铁站位于格子(N,M)的东北角。第二行为K(0 <= K <= 100),表示有k个格子允许对角线穿越。以下K行为允许对角线穿越的格子,分别用一对数表示,空格隔开。
求Nikanor的家到地铁站的最短路径,四舍五入到整数米。
用动态规划:
设f[i][j]是出发点到点a[i][j]的最短路径
f[i][j] = min(f[i-1][j], f[i][j-1]) + 100 //不能从a[i-1][j-1]到a[i][j]
f[i][j] = min(f[i-1][j]+100, f[i][j-1]+100, f[i-1][j-1] + 100√2) //能从a[i-1][j-1]到a[i][j]
但是由于内存限制,用二维数组dp会超内存,由于f[i][j]只赖于f[i-1][j],f[i][j-1],可以用滚动数组。
一个DP,平常如果需要1000×1000的空间,其实根据DP的无后效性,可以开成2×1000,然后通过滚动,获得和1000×1000一样的效果。滚动数组常用于DP之中,在DP过程中,我们在由一个状态转向另一个状态时,很可能之前存储的某些状态信息就已经无用了,例如在01背包问题中,从理解角度讲我们应开DP[i][j]的二维数组,第一维我们存处理到第几个物品,也就是阶段了,第二维存储容量,但是我们获得DP[i],只需使用DP[i - 1]的信息,DP[i - k],k>1都成了无用空间,因此我们可以将数组开成一维就行,迭代更新数组中内容,滚动数组也是这个原理,目的也一样,不过这时候的问题常常是不可能缩成一维的了,比如一个DP[i][j]需要由DP[i - 1 ][k],DP[i - 2][k]决定,i<n,0<k<=10;n <= 100000000;显然缩不成一维,正常我们应该开一个DP[100000005][11]的数组,结果很明显,超内存,其实我们只要开DP[3][11]就够了DP[i%3][j]由DP[(i - 1)%3][k]和DP[(i - 2)%3][k]决定,空间复杂度差别巨大。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> //for memset 4 #include <cmath> //for sqrt 5 #include <algorithm> //for min 6 using namespace std; 7 int main() 8 { 9 int n, m; 10 scanf("%d %d", &n, &m); 11 bool pass[m+1][n+1]; //pass[i][j]标记能不能通过 12 memset(pass, 0, sizeof(pass)); //pass下标与输入的n,m相反 13 int k; 14 scanf("%d", &k); 15 for (int i = 0; i < k; ++i) 16 { 17 int row, col; 18 scanf("%d %d", &row, &col); 19 pass[col][row] = 1; 20 } 21 double f[2][n+1]; //滚动数组 22 memset(f, 0, sizeof(f)); 23 for (int i = 1; i <= n; ++i) 24 f[0][i] = i * 100.0; 25 for (int i = 1; i <= m; ++i) 26 { 27 f[i%2][0] = i * 100.0; 28 for (int j = 1; j <= n; ++j) 29 { 30 if (!pass[i][j]) 31 f[i%2][j] = min(f[(i-1)%2][j], f[i%2][j-1]) + 100.0; 32 else 33 f[i%2][j] = min(f[(i-1)%2][j]+100.0, min(f[i%2][j-1]+100.0, f[(i-1)%2][j-1]+100*sqrt(2.0))); 34 } 35 } 36 printf("%d\n", (int)(f[m%2] + 0.5)); 37 return 0; 38 }
另外在讨论贴看到了另一种更好的解法:算法2:
可以发现,如果我们只走直边的话,要走(N+M)*100长度。如果走C条斜边,那么要走(C*141.4213562373)+(N+M-C*2)*100 的长度。那么显然我们要尽可能使C更大,即多走斜边。
这样可以转化为经典的LIS模型。即把所有的斜边按照坐标排序,然后求最长的上升序列(x,y都要严格递增),走这样的斜边一定是最优的策略。于是我们可以求出C。
结果就是(C*141.4213562373)+(N+M-C*2)*100。
Vijos 1336其实就是这道题的数据加大版。对于较小的K和很大的N,M,只能用算法2解决。
相关文章推荐
- 1119. Metro(动态规划,滚动数组)
- POJ 3624 Charm Bracelet(DP动态规划+滚动数组)
- 【Java】【滚动数组】【动态规划】UVA - 11137 - Ingenuous Cubrency
- hdu1024(动态规划+滚动数组优化)
- hdu 1024(滚动数组+动态规划)
- 最大子段-n上找m个子段的和为最大-动态规划-二维dp+滚动数组dp优化
- ural 1119. Metro(动态规划)
- 动态规划(入门,滚动数组,记录的都是状态):SWUSTACM-1010 魔兽争霸之最后的反击
- 【USACO3.1.6】邮票 动态规划/滚动数组
- 【动态规划】【滚动数组】【搜索】Playrix Codescapes Cup (Codeforces Round #413, rated, Div. 1 + Div. 2) D. Field expansion
- 背包问题 动态规划 滚动数组实现
- POJ1159(动态规划+滚动数组)
- 杭电ACM OJ 1024 Max Sum Plus Plus 动态规划 二维dp+滚动数组dp优化
- 【动态规划】【滚动数组】Educational Codeforces Round 26 D. Round Subset
- poj 3666 Making the Grade 动态规划+滚动数组
- 【算法设计与数据结构】动态规划入门——URAL 1119 Metro
- URAL 1119 Metro (DP动态规划)
- 守望者的逃离 动态规划+滚动数组
- [TYVJ1061] Mobile Service|动态规划|滚动数组
- HDU 3008 Warcraft,动态规划,滚动数组