UVa 10599lis dp,记忆化搜索

Posted ╰追憶似水年華ぃ╮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVa 10599lis dp,记忆化搜索相关的知识,希望对你有一定的参考价值。

UVa 10599

题意:

  给出r*c的网格,其中有些格子里面有垃圾,机器人从左上角移动到右下角,只能向右或向下移动。问机器人能清扫最多多少个含有垃圾的格子,有多少中方案,输出其中一种方案的格子编号。格子编号是从 左上角第一个开始,一行一行的按自然数顺序编。起始行列是第一行第一列。所以例如一个格子的行列号为(ro,co),那么它的编号为bh=(ro-1)*column+co,其中column指这个格子有多少列。(我觉得原题里面有个错误,题目叙述倒数第二行应该是41(6,6)不是41(6,7))。

题解:  

  显然,格子的编号都是递增的,每个含有垃圾的格子的编号也是递增的,要求能扫多少个有垃圾的格子,其实可以看成求这些垃圾格子编号的一个最长上升子序列(lis),而且这和普通格子没关系。需要注意的就是求lis时格子编号大的一定不能在编号小的左边,可以在同一列上。因为机器人只能向下或向右走。所以判断的时候要判断一下两个格子的列大小,这个也可以转化为比较编号的大小:(bh-1)%colum,可以算一下这个式子正好算出格子的 列号-1。当然,这里可以用其它办法判断。然后就是用dp[]数组记录最多清扫多少个格子,用save[]记录垃圾格子的编号,用num[]数组记录方案总数(就是看成普通lis求法),用patn[]数组记录当前状态是从哪里转移过来的,也就是记录路径。

详见代码:

技术分享
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn = 107;
 6 int Map[maxn][maxn];//存那个格子有垃圾
 7 int dp[maxn*maxn], num[maxn*maxn], path[maxn*maxn], save[maxn*maxn];//如上文所述
 8 int r, c, n;//格子行、列,有多少个垃圾格子
 9 
10 void print(int cur)//递归输出
11 {
12     if (path[cur] != -1)
13         print(path[cur]);
14     if (cur != n - 1 || Map[r][c])//因为从n-1开始调用,当右下角格子不是垃圾格子时不需要输出(cur!=n-1),是垃圾格子时需要输出(Map[r][c])
15         printf(" %d", save[cur]);
16 }
17 
18 int main()
19 {
20     int cas = 1;
21     while (cin >> r >> c)
22     {
23         memset(Map, 0, sizeof(Map));
24         memset(save, 0, sizeof(save));
25         if (r == -1 && c == -1) break;
26         int a, b;
27         while (cin >> a >> b)
28         {
29             if (a == 0 && b == 0) break;
30             Map[a][b] = 1;
31         }
32         n = 0;
33         for (int i = 1; i <= r; i++)
34             for (int j = 1; j <= c; j++) {
35                 if (Map[i][j])
36                     save[n++] = (i - 1)*c + j;//为垃圾格子编号
37             }
38         if (!Map[r][c]) save[n++] = r*c;//因为最后要到达右下角,所以不管右下角是不是垃圾格子,都把它看成有,求"lis"过程好办点
39         for (int i = 0; i <= n; i++) {//dp过程,和求lis过程类似
40             dp[i] = 1; num[i] = 1; path[i] = -1;
41             for (int j = 0; j < i; j++) {
42                 if (((save[j] - 1) % c) <= ((save[i] - 1) % c)) {//比较列
43                     if (dp[i] == dp[j] + 1) {//此时相当于又多了一种到i状态(第i个数)的方案数,那么直接累加num[j]
44                         num[i] += num[j];
45                     }
46                     else if (dp[i] < dp[j] + 1) {//此时状态可更新
47                         dp[i] = dp[j] + 1;//更新状态
48                         num[i] = num[j];//改为新状态的方案
49                         path[i] = j;//由于有新的状态,所以记录到当前状态的上一个状态位置
50                     }
51                 }
52             }
53         }
54         if (!Map[r][c]) dp[n - 1]--;//当右下角那个不是垃圾格子时,能清理的垃圾格子数-1
55         printf("CASE#%d: %d %d", cas++, dp[n - 1], num[n - 1]);
56         print(n - 1);//输出路径
57         printf("\n");
58     }
59     return 0;
60 }
UVa 10599 code_1

 

以上是关于UVa 10599lis dp,记忆化搜索的主要内容,如果未能解决你的问题,请参考以下文章

uva 10123 - No Tipping dp 记忆化搜索

uva 10891 区间dp+记忆化搜索

UVA 10003 Cutting Sticks 区间DP+记忆化搜索

UVA - 1630 Folding(串折叠)(dp---记忆化搜索)

UVA 10891 Game of Sum(区间DP(记忆化搜索))

UVA - 10559 Blocks 和 Vasya and Binary String CodeForces - 1107E (dp OR 记忆化搜索)