Codeforces 41D Pawn【dp+记录路径】

D. Pawn
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

On some square in the lowest row of a chessboard a stands a pawn. It has only two variants of moving: upwards and leftwards or upwards and rightwards. The pawn can choose from which square of the lowest row it can start its journey. On each square lay from 0 to 9 peas. The pawn wants to reach the uppermost row having collected as many peas as possible. As there it will have to divide the peas between itself and its k brothers, the number of peas must be divisible by k + 1. Find the maximal number of peas it will be able to collect and which moves it should make to do it.

The pawn cannot throw peas away or leave the board. When a pawn appears in some square of the board (including the first and last square of the way), it necessarily takes all the peas.

Input

The first line contains three integers n, m, k (2 ≤ n, m ≤ 100, 0 ≤ k ≤ 10) — the number of rows and columns on the chessboard, the number of the pawn's brothers. Then follow n lines containing each m numbers from 0 to 9 without spaces — the chessboard's description. Each square is described by one number — the number of peas in it. The first line corresponds to the uppermost row and the last line — to the lowest row.

Output

If it is impossible to reach the highest row having collected the number of peas divisible by k + 1, print -1.

Otherwise, the first line must contain a single number — the maximal number of peas the pawn can collect given that the number must be divisible by k + 1. The second line must contain a single number — the number of the square's column in the lowest row, from which the pawn must start its journey. The columns are numbered from the left to the right with integral numbers starting from 1. The third line must contain a line consisting of n - 1 symbols — the description of the pawn's moves. If the pawn must move upwards and leftwards, print L, if it must move upwards and rightwards, print R. If there are several solutions to that problem, print any of them.

Examples
Input
3 3 1
123
456
789
Output
16
2
RL
Input
3 3 0
123
456
789
Output
17
3
LR
Input
2 2 10
98
75
Output
-1

题目大意:

给你一个N*M的矩阵,其中每个格点中包含0-9中一个数字,问从最下边那一层找到一个起点,一直向上走(向上走只有两种方式,要么斜左上,要么斜右上),询问一个最大值,其走到最上边一层之后,其和为k+1的倍数。并且输出起点位子,以及路径怎样走的。


思路:


1、爆搜明显是不可行的,考虑dp。设定dp【i】【j】【k】表示走到点(i,j)处,其和为k是否有这样的情况,如果有,dp【i】【j】【k】=1,否则为0.


2、那么不难想到其状态转移方程:

dp【i】【j】【k】=max(dp【i+1】【j-1】【k-a【i】【j】】,dp【i+1】【j+1【k-a【i】【j】】);

表示当前状态可以从下一层的左边或者是右边转移过来。对应如果其中有一个状态是1,那么对应dp【i】【j】【k】也就变成了1.


3、然后我们在最上边一层维护最大可行解,输出出来之后,对应回溯过程,记录到数组中,输出即可。


Ac代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int dp[102][102][1005];
char a[102][102];
char ans[1500];
int main()
{
    int n,m,kk;
    while(~scanf("%d%d%d",&n,&m,&kk))
    {
        memset(dp,0,sizeof(dp));
        for(int i=0;i<n;i++)
        {
            scanf("%s",a[i]);
        }
        for(int i=0;i<m;i++)
        {
            dp[n-1][i][a[n-1][i]-'0']=1;
        }
        for(int i=n-2;i>=0;i--)
        {
            for(int j=0;j<m;j++)
            {
                int now=a[i][j]-'0';
                for(int k=now;k<1005;k++)
                {
                    int l=0,r=0;
                    if(j-1>=0)l=dp[i+1][j-1][k-now];
                    if(j+1<m)r=dp[i+1][j+1][k-now];
                    dp[i][j][k]=max(l,r);
                }
            }
        }
        int output=-1;
        int pos;
        for(int i=0;i<m;i++)
        {
            for(int k=0;k<1005;k++)
            {
                if(dp[0][i][k]==1&&k%(kk+1)==0)
                {
                    if(k>output)
                    {
                        output=k;
                        pos=i;
                    }
                }
            }
        }
        printf("%d\n",output);
        if(output>-1)
        {
            int cont=0;
            int tmp=output;
            for(int i=1;i<n;i++)
            {
                int l=0,r=0;
                if(pos-1>=0)
                {
                    l=dp[i][pos-1][tmp-a[i-1][pos]+'0'];
                }
                if(pos+1<m)
                {
                    r=dp[i][pos+1][tmp-a[i-1][pos]+'0'];
                }
                if(l==1)
                {
                    ans[cont++]='R';
                    tmp-=a[i-1][pos]-'0';
                    pos=pos-1;
                    continue;
                }
                if(r==1)
                {
                    ans[cont++]='L';
                    tmp-=a[i-1][pos]-'0';
                    pos=pos+1;
                }
            }
            printf("%d\n",pos+1);
            for(int i=cont-1;i>=0;i--)
            {
                printf("%c",ans[i]);
            }
            printf("\n");
        }
    }
}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
区间DP是一种动态规划的方法,用于解决区间范围内的问题。在Codeforces竞赛中,区间DP经常被用于解决一些复杂的字符串或序列相关的问题。 在区间DP中,dp[i][j]表示第一个序列前i个元素和第二个序列前j个元素的最优解。具体的转移方程会根据具体的问题而变化,但是通常会涉及到比较两个序列的元素是否相等,然后根据不同的情况进行状态转移。 对于区间长度为1的情况,可以先进行初始化,然后再通过枚举区间长度和区间左端点,计算出dp[i][j]的值。 以下是一个示例代码,展示了如何使用区间DP来解决一个字符串匹配的问题: #include <cstdio> #include <cstring> #include <string> #include <iostream> #include <algorithm> using namespace std; const int maxn=510; const int inf=0x3f3f3f3f; int n,dp[maxn][maxn]; char s[maxn]; int main() { scanf("%d", &n); scanf("%s", s + 1); for(int i = 1; i <= n; i++) dp[i][i] = 1; for(int i = 1; i <= n; i++) { if(s[i] == s[i - 1]) dp[i][i - 1] = 1; else dp[i][i - 1] = 2; } for(int len = 3; len <= n; len++) { int r; for(int l = 1; l + len - 1 <= n; l++) { r = l + len - 1; dp[l][r] = inf; if(s[l] == s[r]) dp[l][r] = min(dp[l + 1][r], dp[l][r - 1]); else { for(int k = l; k <= r; k++) { dp[l][r] = min(dp[l][r], dp[l][k] + dp[k + 1][r]); } } } } printf("%d\n", dp[n]); return 0; } 希望这个例子能帮助你理解区间DP的基本思想和应用方法。如果你还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值