您的位置:首页 > 其它

UVA 10564 Paths through the Hourglass

2013-01-19 17:59 477 查看
大意:有一个沙漏,从第一行开始走,每次往下走一行,往左或者往右走一列,不能走出沙漏。你的目标是让沿途经过的所有整数之和恰好为一个给定的整数。求出符合条件的路径条数。

思路:求路径条数,这很常见,令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");
}*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: