uva 10564 - Paths through the Hourglass 沙漏里的路径(类似01背包问题)

题意:给出一个沙漏形状的2(n - 1)行矩阵,并给出一个总全值和每个坐标的权值,每个位置可以走向下一行与它相邻的两个或一个位置(参见题目中的图),请找出有多少调路径上的权值和等于给定的总权值,并输出字典序最小的一条路径的起始位置 和方案。

分析:数字三角的升级版,本题需要记录每个点所有能出现的情况,所以开一个三维数组,dp[i][j][k]表示在i,j这个位置权值和为k的走法有多少种,状态转移公式dp[i][j][k] = dp[i+1][j][k - num[i][j]] + dp[i + 1][j + 1][k - num[i][j]],因为字典序最小,所以自底向上进行数字三角形上的01背包,递归打印路径。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 50;
ll dp[N][N][510];
int n, s, str[N][N];
int abs(int x){ return x<0?-x:x; }
void printf_ans(int x, int y, int v)
{
    if(x==2*n-1) return ;
    int ss = str[x][y];
    if(dp[x+1][y][v-ss]) { printf("L"); printf_ans(x+1,y,v-ss); }
    else { printf("R"); printf_ans(x+1,y+1,v-ss); }
}
int main ()
{
    while(scanf("%d %d",&n, &s), s+n)
    {
        for(int i = 1; i <= n; i++)
            for(int j = i; j <= n; j++)
                scanf("%d",&str[i][j]);
        for(int i = n+1; i <= 2*n-1; i++)
            for(int j = n; j <= i; j++)
                scanf("%d",&str[i][j]);
        memset(dp,0,sizeof(dp));
        for(int i = n; i <= 2*n-1; i++)
            dp[2*n-1][i][str[2*n-1][i]] = 1;
        for(int i = 2*n-2; i >= n; i--)
            for(int j = n; j <= i; j++)
                for(int v = str[i][j], k = str[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++)
                for(int v = str[i][j], k = str[i][j]; k <= s; k++)
                    dp[i][j][k] = dp[i+1][j][k-v]+dp[i+1][j+1][k-v];
        long long 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);
            printf_ans(1,i,s);
            break;
        }
        printf("\n");
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值