CF41D Pawn 题解

CF41D Pawn 题解

题目链接:CF41D Pawn

题意:国际象棋棋盘最底行站了一个兵。 它只有两种行动方式: 向上左或向上右走。 它可以选择从最低行哪个节点开始他的旅程。 每个格子上有0-9颗豌豆,而士兵想移动到最上一行并且积累到尽可能多的豌豆。同时,因为这个士兵必须把豌豆平均分给自己和他的k个兄弟,他所收集到的豌豆必须是k+1的倍数。请找到他可以收集到的最多豌豆,并确定他的操作序列。

规定士兵不能手动扔出豌豆,并且他必须捡起所到达的每一个格子的所有豌豆。

输入格式: 第一行三个整数 n , m , k ( 2 ≤ n , m ≤ 100 , 0 ≤ k ≤ 10 ) n,m,k(2 \le n,m \le 100, 0 \le k \le 10) n,m,k(2n,m100,0k10) 行数、列数、士兵的兄弟们。 接下来一个 n × m n \times m n×m 的矩阵,每个元素均是0-9的整数(不空格),描述该格的豌豆。第一行被认为是最上一行,最后一行被认为是最下一行。

输出格式:

如果不能收集到k+1倍数的豌豆,输出-1. 否则,输出第一行一个整数,为最多豌豆数;第二行一个整数,为士兵开始移动的位置;第三行包括n-1个字母L 或 R,表示士兵的行动序列。

如果有多种收集到相同且是k+1倍数数量的豌豆,你可以任意输出一种方案。

d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k] 为走到第 i i i 行第 j j j 列且恰好取了 k k k 个的方案数

这里不用求方案数,就用bool即可

不习惯从下往上跑就翻转一下

答案就是所有的最后一行所有的 d p [ 1 ] [ j ] [ c ]   s . t .   k ∣ c dp[1][j][c] \bold{\ s.t. \ } k\mid c dp[1][j][c] s.t. kc

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(115)
int n,m,c;
int a[N][N];
bool dp[N][N][N*10];
char d[N][N][N*10];
void print(int i,int j,int k)
{
    if(i==1)
    {
        printf("%lld\n",j);
        return;
    }
    char di=d[i][j][k];
    if(di=='L')print(i-1,j+1,k-a[i][j]);
    else print(i-1,j-1,k-a[i][j]);
    putchar(d[i][j][k]);
}
signed main()
{
    scanf("%lld%lld%lld",&n,&m,&c);
    for(int i=n; i>=1; i--)
        for(int j=1; j<=m; j++)
            scanf("%1lld",&a[i][j]);
    for(int i=1; i<=m; i++)
        dp[1][i][a[1][i]]=1;
    for(int i=2; i<=n; i++)
        for(int j=1; j<=m; j++)
            for(int k=9*n; k>=a[i][j]; --k)
            {
                if(j-1>=1&&dp[i-1][j-1][k-a[i][j]])
                {
                    dp[i][j][k]|=dp[i-1][j-1][k-a[i][j]];
                    d[i][j][k]='R';
                }
                if(j+1<=m&&dp[i-1][j+1][k-a[i][j]])
                {
                    dp[i][j][k]|=dp[i-1][j+1][k-a[i][j]];
                    d[i][j][k]='L';
                }
            }
    for(int k=(9*n/(c+1))*(c+1); k>=0; k-=c+1)
        for(int i=1; i<=m; i++)
            if(dp[n][i][k])
            {
                printf("%lld\n",k);
                print(n,i,k);
                return 0;
            }
    puts("-1");
    return 0;
}

转载请说明出处

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值