链接
传送门
题意
给出一个沙漏,求从顶至底经过数字的和为定值的路径数目。如果数目不为零,输出字典序最小的一条。
思路
类似于背包的dp,对于每个点保存从当前点到沙漏底部不同值的路径数目。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <queue> using namespace std;
typedef long long LL; const int maxn = 21; const int maxs = 505; int a[maxn << 1][maxn]; LL dp[maxn << 1][maxn][maxs];
int main() { int n, s; while (~scanf("%d%d", &n, &s) && (n || s)) { for (int i = 1; i < n; ++i) { for (int j = 1; j <= n - i + 1; ++j) { scanf("%d", &a[i][j]); } } for (int i = 1; i <= n; ++i) { for (int j = 1; j <= i; ++j) { scanf("%d", &a[n + i - 1][j]); } } memset(dp, 0, sizeof dp); int n2 = (n << 1) - 1; for (int i = 1; i <= n; ++i) { dp[n2][i][a[n2][i]] = 1; } for (int i = n2 - 1; i >= n; --i) { for (int j = 1; j <= i - n + 1; ++j) { for (int k = a[i][j]; k <= s; ++k) { dp[i][j][k] = dp[i + 1][j][k - a[i][j]] + dp[i + 1][j + 1][k - a[i][j]]; } } } LL ans = 0; for (int i = n - 1; i >= 1; --i) { for (int j = 1; j <= n - i + 1; ++j) { for (int k = a[i][j]; k <= s; ++k) { dp[i][j][k] = 0; if (j > 1) { dp[i][j][k] += dp[i + 1][j - 1][k - a[i][j]]; } if (j < n - i + 1) { dp[i][j][k] += dp[i + 1][j][k - a[i][j]]; } } if (i == 1) { ans += dp[i][j][s]; } } } printf("%lld\n", ans); if (ans > 0) { for (int i = 1; i <= n; ++i) { if (dp[1][i][s] > 0) { printf("%d ", i - 1); int p = i, ss = s; for (int j = 1; j < n; ++j) { ss -= a[j][p]; if (p > 1 && dp[j + 1][p - 1][ss] > 0) { putchar('L'); --p; } else { putchar('R'); } } for (int j = n; j < n2; ++j) { ss -= a[j][p]; if (dp[j + 1][p][ss] > 0) { putchar('L'); } else { ++p; putchar('R'); } } break; } } } puts(""); } return 0; }
|