1. 程式人生 > >5920 Ugly Problem 大數減法模擬+貪心

5920 Ugly Problem 大數減法模擬+貪心

1.題意:給你一個數字N,讓你把它拆成n(n<=50)個迴文數字的和,並輸出這些迴文數字(N<=10^1000)

2.分析:

(1)對於一個數字,我們先找儘可能接近他的會迴文數字,然後減去。但是這個迴文數字太難找了,怎麼辦?我們可以把當前數字前半部分對稱到後面去,比如123 其對應的會迴文數字為121。但是這裡就面臨一個問題:120對應的121比120大,所以我們這裡可以把12減1再對稱為111就可以了

(2)為了防止冗雜的判斷,我們為了保證迴文 + 小於原數字,直接取前一半減1在對稱。如10000->取前一半100->減99->對稱9999     不斷取剩餘數字的迴文,知道原數字減為0即可。

(3)特判:13取前一半減1對稱後變成了00,也就是如果減1後變為了0,這樣的只有1,所以保持1不動即可。還有10這個數字,保持不動對稱為11,減1為00,都不符合,所以特判為 9 + 1;

3.程式碼:

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000 + 7;
char num[maxn],num2[maxn],another[maxn],sub[maxn];
char ans[51][maxn];
char one[2] = "1";
bool judge(char *s){//判斷當前數字是否為迴文數字
   int lens = strlen(s);
   for(int i = 0;i<lens/2;i++){
        if(s[i]!=s[lens - i - 1]){
            return false;
        }
   }
   return true;
}
void Decrease(char *s1,char *s2){//大數減法,s1 - s2並把結果賦值給s1去掉前導0
    int len1 = strlen(s1);
    int len2 = strlen(s2);
    int i = len1-1;
    int j = len2-1;
    int flag = 0;
    while(i>=0&&j>=0){
        if(s1[i] - '0'>=flag){
            s1[i] = s1[i] - flag;
            flag = 0;
        }
        else{
            s1[i] = s1[i]  + 10 - flag;
            flag = 1;
        }
        if(s1[i]>=s2[j]){s1[i] = s1[i] -s2[j] + '0';}
        else{
            s1[i] = s1[i] + 10 - s2[j] + '0';
            flag = 1;
        }
        i--;
        j--;
    }
    while(flag&&i>=0){
        if(s1[i] - '0'>=flag){
            s1[i] = s1[i] - flag;
            flag = 0;
        }
        else{
            s1[i] = s1[i]  + 10 - flag;
            flag = 1;
        }
        i--;
    }
    //cout<<s1<<endl;
    int l = 0;
    bool flagd = false;
    memset(another,0,sizeof(another));
    for(int k = 0;k<len1;k++){//去掉前導0
        if(s1[k]=='0'&&!flagd)continue;
        else if(s1[k]!='0'&&!flagd){
            flagd = true;
            another[l++] = s1[k];
        }
        else if(flagd){
            another[l++] = s1[k];
        }
    }
    if(!l){another[l] = '0';l++;}//減法完為0
    another[l] = '\0';
    strcpy(s1,another);//複製
}
void palindromic(char *s1,char *s2){//取s1的迴文串s2
    int len1 = strlen(s1);
    if(len1==2&&s1[0]=='1'&&s1[1]=='0'){//特判
        s2[0] = '9';
        s2[1] = '\0';
        return;
    }
    int len2 = (len1&1)?len1/2 + 1:len1/2;
    for(int i = 0;i<len2;i++){//取前一半
        s2[i]  = s1[i];
    }
    s2[len2] = '\0';
    Decrease(s2,one);//減1
    if(s2[0]=='0'){//判斷1
        s2[0] = '1';
    }
    for(int i = len1-1,j = 0;j<i;i--,j++){
        s2[i] = s2[j];//對稱
    }
    s2[len1] = '\0';
}
int main()
{
    int T;
    scanf("%d",&T);
    int t = 0;
    while(T--){
        scanf("%s",num);
        t++;
        int le = 0;
        while(num[0]!='0'&&le<=50){
            le++;
            //cout<<"num:"<<num<<endl;
            if(judge(num)){//當前為迴文,直接結束
                strcpy(ans[le++],num);
                break;
            }
            memset(sub,0,sizeof(sub));
            palindromic(num,sub);//取回文數字sub
            //cout<<"sub:"<<sub<<endl;
            strcpy(ans[le++],sub);//儲存結果sub
            Decrease(num,sub);//num - sub
        }
        printf("Case #%d:\n%d\n",t,le);
        for(int i = 0;i<le;i++){
            printf("%s\n",ans[i]);
        }
    }
    return 0;
}