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.
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.
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.
3 3 1 123 456 789
16 2 RL
3 3 0 123 456 789
17 3 LR
2 2 10 98 75
-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");
}
}
}