题意:
有一个沙漏,从第一行开始走,每次往下走一行,往左或者往右走一列,不能走出沙漏。
你的目标是让沿途经过的所有整数之和恰好为一个给定的整数。输出符合条件的路径条数。
思路:
求路径条数,这很常见,令dp[i][j][s]表示以第i行,j列的元素为起点,累加的和为s的路径条数,先令终点的值为1,反向从终点向起点递推,求得答案。
状态:dp[i][j][k]从(i,j)出发路径上的和为k的路径数目。
状态转移:dp[i][j][k] = dp[i+1][j][k-v]+dp[i+1][j+1][k-v];
这题对于a[i][j]坐标构造很巧妙,参考了这个博客的代码。
http://hi.baidu.com/arosliu/item/e500c8e5b7a5a0c3bbf37d8e
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 50;
ll dp[50][50][505];
int n, s, a[N][N];
void print_path(int x,int y,int sum) {
if(x == 2*n - 1)
return;
int v = a[x][y];
if(dp[x+1][y][sum-v]) {
putchar('L');
print_path(x+1,y,sum-v);
}else {
putchar('R');
print_path(x+1,y+1,sum-v);
}
}
int main() {
while(scanf("%d%d",&n,&s) != EOF && (n || s)) {
for(int i = 1; i <= n; i++)
for(int j = i; j <= n; j++)
scanf("%d",&a[i][j]);
for(int i = n+1; i <= 2*n-1; i++)
for(int j = n; j <= i; j++)
scanf("%d",&a[i][j]);
memset(dp,0,sizeof(dp));
for(int i = n; i <= 2*n-1; i++) {
int tmp = a[2*n-1][i];
dp[2*n-1][i][tmp] = 1;
}
for(int i = 2*n-2; i >= n; i--) {
for(int j = n; j <= i; j++) {
int v = a[i][j];
for(int k = a[i][j]; k <= s; k++)
dp[i][j][k] = dp[i+1][j][k-v] + dp[i+1][j+1][k-v];
}
}
for(int i = n-1; i >= 1; i--) {
for(int j = i; j <= n; j++) {
int v = a[i][j];
for(int k = a[i][j]; k <= s; k++) {
dp[i][j][k] = dp[i+1][j][k-v] + dp[i+1][j+1][k-v];
}
}
}
ll ans = 0;
for(int i = 1; i <= n; i++) {
ans += dp[1][i][s];
}
printf("%lld\n",ans);
for(int i = 1; i <= n; i++) {
if(dp[1][i][s]) {
printf("%d ",i-1);
print_path(1,i,s);
break;
}
}
printf("\n");
}
return 0;
}
本文介绍了一种求解特定沙漏形网格中路径数量的方法,通过动态规划算法实现,确保从起点到终点的路径上整数之和等于给定值。文章详细解释了状态转移方程,并提供了完整的代码实现。
5万+

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



