大意:有一个沙漏,从第一行开始走,每次往下走一行,往左或者往右走一列,不能走出沙漏。你的目标是让沿途经过的所有整数之和恰好为一个给定的整数。求出符合条件的路径条数。
思路:求路径条数,这很常见,令d[i][j][s]表示以第i行,j列的元素为起点,累加的和为s的路径条数,从上往下走,只要走到终点,则令终点的值为1,这样在搜索时就可以很方便的求出结果。
这一题还有一个问题不好解决,如果只有上三角形的话,很好解决,那么多了一个下三角形,那么选择向左走还是向右走的时候,方向可能会紊乱,所以我我们可以另外开两个数组L,R来表示当前点的左边应该怎么操作,右边应该怎么操作。
然后记忆化搜索时,注意没有越界,而且走到最底层时,要判断累加和是否为初始时的s,是,路径为1,否,路径为0。
打印路径时,从第一行开始扫,遇到第一个非0数则退出,然后递归打印路径。
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <string>
#include <algorithm>
using namespace std;
int n, s;
typedef long long LL;
LL d[50][50][510];
int vis[50][50][510];
int L[50][50], R[50][50];
int A[50][50];
void init()
{
memset(A, -1, sizeof(A));
memset(vis, 0, sizeof(vis));
memset(L, 0, sizeof(L));
memset(R, 0, sizeof(R));
}
void read_case()
{
init();
for(int i = 1; i < n; i++)
{
for(int j = 1; j <= (n-i+1); j++)
{
scanf("%d", &A[i][j]);
L[i][j] = j-1;
R[i][j] = j;
}
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= i; j++)
{
scanf("%d", &A[i+n-1][j]);
L[n+i-1][j] = j;
R[n+i-1][j] = j+1;
}
}
}
LL dp(int i, int j, int s)
{
LL &ans = d[i][j][s];
if(vis[i][j][s]) return ans;
vis[i][j][s] = 1;
if(A[i][j] == -1 || s < 0) ans = 0; //边界条件
else if(i == 2*n-1) //边界条件
{
if(s == A[i][j]) ans = 1;
else ans = 0;
}
else
{
s -= A[i][j];
ans = dp(i+1, L[i][j], s) + dp(i+1, R[i][j], s);
}
return ans;
}
void print_ans(int i, int j, int s)
{
if(i == 2*n-1)
{
printf("\n");
return ;
}
else
{
s -= A[i][j];
if(dp(i+1, L[i][j], s) > 0) //如果存在路径
{
printf("L");
print_ans(i+1, L[i][j], s);
}
else
{
printf("R");
print_ans(i+1, R[i][j], s);
}
}
}
void solve()
{
int i, j;
read_case();
LL ans = 0;
for(i = 1; i <= n; i++) ans += dp(1, i, s);
printf("%lld\n", ans);
if(ans == 0) { printf("\n"); return ;}
for(j = 1; dp(1, j, s) == 0; j++) ; //从左往右第一个不为0的数
printf("%d ", j-1);
print_ans(1, j, s);
}
int main()
{
while(scanf("%d%d", &n, &s) && (n || s))
{
solve();
}
return 0;
}
/*void print_ans() //非递归打印路径
{
int i, j;
for(j = 1; dp(1, j, s) == 0; j++) ;
printf("%d ", j-1);
for(int i = 1; i < 2*n-1; i++)
{
s -= A[i][j];
int c = dp(i+1, L[i][j], s);
if(c > 0)
{
printf("L");
j = L[i][j];
}
else
{
printf("R");
j = R[i][j];
}
}
printf("\n");
}*/
本文探讨了一种独特的问题,即在沙漏状的二维矩阵中,从顶点出发,仅能向左或向右移动,寻找一条路径使得经过的所有整数之和等于给定的目标值,并计算满足条件的路径数量。文章详细介绍了使用动态规划和记忆化搜索的方法解决问题,同时提供了代码实现。通过案例演示了如何应用这些算法,以清晰地理解问题的解决过程。

469

被折叠的 条评论
为什么被折叠?



