转移类似背包问题,上下三角分开处理。要求字典序最小,所以要从下到上DP。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL long long
LL d[41][21][505];
int N,S;
int a[41][21];
bool C(int i,int j){
if(i<=N){
if(j>=1&&j<=N-i+1) return 1;
return 0;
}
else {
if(j>=1&&j<=i-N+1) return 1;
return 0;
}
}
LL dp(int i,int j,int s){
if(d[i][j][s]!=-1) return d[i][j][s];
if(!C(i,j)||s<a[i][j]) return d[i][j][s]=0;
d[i][j][s]=0;
if(i==2*N-1){
if(s==a[i][j]){
return d[i][j][s]=1;
}
return d[i][j][s]=0;
}
if(i<N) d[i][j][s]=dp(i+1,j-1,s-a[i][j])+dp(i+1,j,s-a[i][j]);
else d[i][j][s]=dp(i+1,j,s-a[i][j])+dp(i+1,j+1,s-a[i][j]);
return d[i][j][s];
}
int main(){
while(~scanf("%d%d",&N,&S)){
if(!N&&!S) break;
memset(d,-1,sizeof(d));
for(int i=1;i<=N;i++){
for(int j=1;j<=N-i+1;j++){
scanf("%d",&a[i][j]);
}
}
for(int i=2;i<=N;i++){
for(int j=1;j<=i;j++){
scanf("%d",&a[i+N-1][j]);
}
}
LL ans=0;
for(int i=1;i<=N;i++){
ans+=dp(1,i,S);
}
printf("%lld\n",ans);
int pos=0;
for(int i=1;i<=N;i++){
if(dp(1,i,S)>0){
pos=i;
break;
}
}
if(ans==0) printf("\n");
else{
printf("%d ",pos-1);
for(int i=1;i<N;i++){
S-=a[i][pos];
if(dp(i+1,pos-1,S)){
printf("L");
pos-=1;
}
else {
printf("R");
}
}
for(int i=N;i<2*N-1;i++){
S-=a[i][pos];
if(dp(i+1,pos,S)){
printf("L");
}
else {
printf("R");
pos+=1;
}
}
printf("\n");
}
}
return 0;
}
/*
2 9
1 2
3
4 5
*/
本文探讨了转移类背包问题的解决方法,特别关注如何通过从下到上的动态规划策略来确保得到字典序最小的解。详细介绍了问题定义、解题策略、代码实现以及实例应用。
772

被折叠的 条评论
为什么被折叠?



