二次dp,还算好想。
先第一遍dp找出最后一个数字最小是几。
dpf[i]=max{j}+1(dpf[j],dpf[j]+1,…,j位组成的数字小于j+1,j+2,…,i位组成的数字。
在第二遍dp,找出第一个数字最大是几。
dpb[i]=max{j}(I,i+1,…,j为组成的数字小于j+1,j+2,…,dpb[i+2]位组成的数字。
按轨迹输出。
!记住:每次都要将两个数组清零!(坑了我半天)
代码:
#include<cstdio>
#include<cstring>
using namespace std;
int dpf[90]={0},dpb[90]={0};
char a[90];
int max(int x,int y){
return(x>y)?x:y;
}
int cmp(int x1,int y1,int x2,int y2){
while(a[x1]=='0' && x1<=y1)x1++;
while(a[x2]=='0' && x2<=y2)x2++;
if(x1>y1 && x2>y2)return 1;
if(y1-x1>y2-x2)return 0;
if(y1-x1<y2-x2)return 1;
for(int i=0;i<=y1-x1;i++){
if(a[x2+i]>a[x1+i])return 1;
if(a[x1+i]>a[x2+i])return 0;
}
return 0;
}
int main(){
scanf("%s",a);
while(strlen(a)!=1 || a[0]!='0'){
int l=strlen(a);
dpf[0]=0;
for(int i=1;i<l;i++){
dpf[i]=0;
for(int j=0;j<i;j++)
if(j+1>dpf[i] && cmp(dpf[j],j,j+1,i))
dpf[i]=j+1;
}
// for(int i=0;i<l;i++)printf("%d ",dpf[i]);printf("\n");
int tl=dpf[l-1];
memset(dpb,0,sizeof(dpb));
dpb[tl]=l-1;
for(int i=tl-1;a[i]=='0';i--)
dpb[i]=l-1;
for(int i=tl-1;i>=0;i--){
for(int j=i;j<=tl-1;j++){
if(cmp(i,j,j+1,dpb[j+1]))
dpb[i] = max(dpb[i], j);
}
}
// for(int i=0;i<l;i++)printf("%d ",dpb[i]);printf("\n");
int cur=dpb[0];
for(int i=0;i<l;){
for(;i<=cur && i<l;i++)printf("%c",a[i]);
if(i<l)printf(",");
cur=dpb[cur+1];
}
printf("\n");
scanf("%s",a);
}
return 0;
}