题意:一个机器人在n * m的网格里面捡垃圾,机器人只能向右或向下走,求出能捡到的垃圾数量的最大值,有多少条路径可以达到最大值,以及输出其中一条路径。
思路:按照题意可以看出,因为机器人只能向右和向下走,所以纵坐标就不重要的,而横坐标是递增的。当将所有拥有垃圾的格子经过计算得到它的一维值(唯一的),得到一组的数组。那就可以转化为求最长上升子序列。但这个LIS的条件是mod(m)要大于前一个。计算数量时,当d[i] = d[j] + 1时,就相当于以i为结束时的最长上升子序列比以j结束时的最长上升子序列大1,那么达到d[i]的路径的数量就为v[i] += v[j];同理当d[i] < d[j] + 1时,v[i] = v[j];至于路径的输出就使用记录数组,递归输出。
自己在初始化将图转化为数组WA了,后来看了别人的改了过来,但还是不懂为什么那样子不对。。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 10005;
int g[105][105], d[MAXN], arr[MAXN], v[MAXN], path[MAXN];
int n, m, cnt;
void init () {
memset(g, 0, sizeof(g));
int a, b;
cnt = 0;
while (scanf("%d %d", &a, &b) && a && b) {
g[a][b] = 1;
//arr[cnt++] = (a - 1) * m + b - 1;
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (g[i][j])
arr[cnt++] = (i - 1) * m + j - 1;
if (!g[n][m])
arr[cnt++] = n * m - 1;
}
void LIS() {
memset(path, -1, sizeof(path));
memset(v, 0, sizeof(v));
memset(d, 0, sizeof(d));
for (int i = 0; i < cnt; i++) {
d[i] = 1, v[i] = 1;
for (int j = 0; j < i; j++)
if (arr[i] % m >= arr[j] % m) {
if (d[i] < d[j] + 1) {
d[i] = d[j] + 1;
path[i] = j;
v[i] = v[j];
}
else if (d[i] == d[j] + 1)
v[i] += v[j];
}
}
if (!g[n][m])
d[cnt - 1]--;
}
void outPut(int u) {
if (path[u] != -1)
outPut(path[u]);
if (u != cnt - 1 || g[n][m])
printf(" %d", arr[u] + 1);
}
int main() {
int t = 1;
while (scanf("%d %d", &n, &m) != EOF) {
if (n == -1 && m == -1)
break;
init();
LIS();
printf("CASE#%d: %d %d", t++, d[cnt - 1], v[cnt - 1]);
outPut(cnt - 1);
printf("\n");
}
return 0;
}