题意:给定一个长度不大于80的数字串,要求对数字串用逗号隔开,使得每个子串表示的数字保证是严格单调递增,且保证分隔后,最后的那个数字最小。当多种情况的最后一个串表示的数相同时,取分隔后的第一个数字最大的,要是第一个数字也相同,那么看分隔后的第二个数字,如此下去,数字前面可以出现0,即000001表示1。
思路:从前往后一个dp求出最后一个数字最小时是多少,这个dp比较好理解,dp[i]表示str[0~i]这个串满足最后一个子串最小时最后一个串的下标起始,即str[dp[i]~i]是最后一个串。接着从后往前第二个dp求出保证最后一个数字最小的情况下满足前面的串尽可能大。这里需要注意对0的处理。
#include <cstdio>
#include <cstring>
#define max(a,b) ((a)>(b)?(a):(b))
#define N 85
char str[N],dp[N],p[N],len;
int cmp(int a,int b,int c){//比较串str[a,b-1]和str[b,c]的大小
int i=a,j=b;
while(i<b-1 && str[i]=='0')
i++;
while(j<c && str[j] == '0')
j++;
if(b-i < c-j+1)
return -1;
else if(b-i > c-j+1)
return 1;
for(;i<b;i++,j++){
if(str[i] < str[j])
return -1;
else if(str[i]>str[j])
return 1;
}
return 0;
}
int zero(int len){
int i;
for(i = len;i>=0;i--){
if(str[i] != '0')
return i;
p[i] = strlen(str)-1;//注意设置紧接在最后一个串前面的0的值
}
return -1;
}
int main(){
freopen("a.txt","r",stdin);
while(scanf("%s",str) && strcmp(str, "0")){
int i,j;
len = strlen(str);
dp[0] = 0;
for(i = 1;i<len;i++){//第一遍dp
for(j = i;j>0;j--)//保证最后一个串尽可能小
if(cmp(dp[j-1],j,i)<0)
break;
dp[i] = j;
}
p[dp[len-1]] = len-1;
len = dp[len-1];//最后一个串除去(因为已经固定)
if((j=zero(len-1)) && j==-1){//如果前面全是0(注意设置紧接在最后一个串前面的0的值)
printf("%s\n",str);
continue;
}
for(i = j;i>=0;i--)
for(j = len;j>i;j--)//保证第一个串尽可能大
if (cmp(i, j, p[j])<0) {
p[i] = j-1;
break;
}
for(i = j = 0;i<strlen(str);i++){//输出
if(i<=p[j])
putchar(str[i]);
if(i==p[j] && i!=strlen(str)-1){
j = i+1;
putchar(',');
}
}
printf("\n");
}
return 0;
}
本文介绍了一种针对数字串的分隔算法,该算法能够确保每个分隔后的子串表示的数字保持严格单调递增,并使得最后一个数字尽可能小。通过两次使用动态规划技术,文章详细解释了如何实现这一目标,并特别关注了对零的处理。
1355

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



