题意:给定一个长度不大于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; }