UVA 10564 - Paths through the Hourglass

这个题最初的想法是用四维数组动规  d【i】【j】【k】【w】  i j  代表 某一个位置 k 代表 到这这个 位置 的 和  w代表 从上一个格子 到这个格子的方向(1代表R 0 代表 L)


在写代码的过程中非常蛋疼。 并且容易错。 所以自己把 第四维 w  去掉 和 背包差不多吧。 就好写了很多。 


思路应该是 从底下 往 上面 转移比较好。 因为 这样到了最上面 很容易就可以判断出是 从哪个数字开始往下走的。


由于自己思维比较习惯 从上往下转移。  就把 对应行的数都换过来就好了。  d【i】【j】【k】  代表 到了 i j  这个格子 和 为 k 有多少种方法。


还有在遍历 k的时候 要注意  k 最大就是 351. 因为  这个沙漏 最高39层。 数字最大 是 9  那么和  最大就是 391. 但是 方法很多。 


自己在WA了一次之后 写了一个 39 行 全是 9的 样例。 遍找出了 错误。 在这种情况下。 可能的情况是 274877906944 种情况。 需要用到longlong 


打印路径就简单点了。 肯定根据状态转移方程 递归写。 从最开始的位置 能往左 尽量往左 这样可以保证 字典序最小。 实在不行再往右。


#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <string>
#include <map>
#include <vector>
#include <set>
#include <queue>
#include <stack>
using namespace std;
#define ll long long
#define maxn 1000+10
#define INF 1<<30
int wh[60][30];
ll d[41][21][400];
int n,sum;
void print_path(int i, int j, int ss){
    if(i == 0)
        return ;
    if(i > n){
        if(d[i-1][j][ss-wh[i][j]]){
            printf("L");
            print_path(i-1,j,ss-wh[i][j]);
        }
        else if(d[i-1][j+1][ss-wh[i][j]]){
            printf("R");
            print_path(i-1,j+1,ss-wh[i][j]);
        }
    }
    if(i <= n){
        if(d[i-1][j-1][ss-wh[i][j]]){
            printf("L");
            print_path(i-1,j-1,ss-wh[i][j]);
        }
        else if(d[i-1][j][ss-wh[i][j]]){
            printf("R");
            print_path(i-1,j,ss-wh[i][j]);
        }
    }
}
int main (){
    while(scanf("%d%d",&n,&sum) != EOF){
        if(n == 0 && sum == 0)
        break;
        memset(wh,-1,sizeof(wh));
        memset(d,0,sizeof(d));
        for(int i = 1; i <= n; i++)
            for(int j = i; j <= n; j++)
                scanf("%d",&wh[i][j]);
        for(int i = n+1; i <= 2*n-1; i++)
            for(int j = 2*n-i; j <= n; j++)
                scanf("%d",&wh[i][j]);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                swap(wh[i][j],wh[2*n-i][j]);
        if(sum > 351){
            printf("0\n\n");
            continue;
        }
        for(int i = 1; i <= n; i++){
            d[1][i][wh[1][i]] = 1;
        }
        for(int i = 2; i <= n; i++){
            for(int j = 1; j <= n; j++){
                if(wh[i][j] == -1)
                    continue;
                if(wh[i-1][j-1] != -1){
                    for(int k = 0; k <= 360; k++){
                        if(d[i-1][j-1][k]){
                            if(k+wh[i][j] > sum)
                                break;
                            else
                                d[i][j][k+wh[i][j]] += d[i-1][j-1][k];
                        }
                    }
                }
                if(wh[i-1][j] != -1){
                    for(int k = 0; k <= 360; k++){
                        if(d[i-1][j][k]){
                            if(k+wh[i][j] > sum)
                                break;
                            else
                                d[i][j][k+wh[i][j]] += d[i-1][j][k];
                        }
                    }
                }
            }
        }
        for(int i = n+1; i <= 2*n-1; i++){
            for(int j = 1; j <= n; j++){
                if(wh[i][j] == -1)
                    continue;
                if(wh[i-1][j] != -1){
                    for(int k = 0; k <= 360; k++){
                        if(d[i-1][j][k]){
                            if(k+wh[i][j] > sum)
                                break;
                            else
                                d[i][j][k+wh[i][j]] += d[i-1][j][k];
                        }
                    }
                }
                if(wh[i-1][j+1] != -1){
                    for(int k = 0; k <= 360; k++){
                        if(d[i-1][j+1][k]){
                            if(k+wh[i][j] > sum)
                                break;
                            else
                                d[i][j][k+wh[i][j]] += d[i-1][j+1][k];
                        }
                    }
                }
            }
        }
        ll ans = 0;
        int w = -1;
        int x,y;
        for(int i = 1; i <= n; i++){
            ans += d[2*n-1][i][sum];
            if(ans != 0 && w == -1){
                w = i-1;
                x = 2*n-1;
                y = i;
            }
        }
        printf("%lld\n",ans);
        if(ans){
            printf("%d ",w);
            print_path(x,y,sum);
        }
        printf("\n");
    }
    return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值