poj-2325 Persistent Numbers ****

/*
* 简略版大整数除法 + 贪心
* 不难发现,如果输入的数含有大于等于10的质数因子,则无解,所以
* ,只需要把输入的数分解为2,3,5,7的幂的形式,然后再由低位向
* 高位进行分配即可(越低位的数字,其值尽可能大)
*
* 开始没好好分析,结果认为 只要 从高位向低位枚举,且满足( ans[i+1] >= ans[i] && ans[i+1]*ans[i] >= 10 )即可,
* 每次枚举一个,就将原数除这个数。。。一次递归求每一位数。 只要求出了一个答案,则答案就是这个。。
* 后来发现这个方法是不行的。。 比如:54454680 找到的答案是:2566777779 有10位。。。 而正确答案是:577777899 有9位
* 所以要找到正确答案,就要求出所有可能的答案然后取最小的那个。。这要就TLE了。。。所以这个方法有不可克服的困难,只好放弃。
* (代码附在后面,以此为鉴)
*
* 然后就用最开始讲的那个算法。。这就很简单了。。。
*
*/

#include
<cstdio>
#include
<cstring>
using namespace std;

const int maxN = 1000 + 5, p2 = 0, p3 = 1, p5 = 2, p7 = 3;
char cData[maxN]; //输入
int data[maxN], len; //个位数放在data[0]
int prime[4] = {2, 3, 5, 7}, ans[5] = {}, lastAns[maxN]={};//ans:各个素因子的个数。。 lastAns:最终答案


//大整数a 除以 i.. 由于i是个位数,,所以这个大整数除法很简单, a最多maxLen位
int inline operate(int *a, int i, int maxLen){
int ansLen = -1;
for(int j=maxLen-1; j>0; j--){
if(a[j] < i){
a[j
-1] += a[j]*10;
a[j]
= 0;
}
else{
a[j
-1] += (a[j] % i) * 10;
a[j]
= a[j] / i;
if(ansLen == -1) ansLen = j;
}
}
if(a[0] % i != 0) return 0;
else{
a[
0] = a[0] / i;
return (ansLen==-1 ? 1 : (ansLen+1)); //注意asnLen要+1
}
}

//求各素因子的个数
bool solve(int *a, int depth, int maxLen){
if(depth == 4 && a[0] == 1){ if(maxLen == 1) return true; else return false; }
else if(depth == 4 && a[0] != 1) return false;
int tmpA[maxN], nextMaxLen = maxLen;
memcpy(tmpA, a,
sizeof(tmpA));
while(true){
int opAns = operate(tmpA, prime[depth], maxLen);
if(opAns){
ans[depth]
++;
nextMaxLen
= opAns;
memcpy(a, tmpA,
sizeof(tmpA));
}
else{ //本素因子已除尽,递归除下一个素因子
return solve(a, depth+1, nextMaxLen);
}
}
}

//求最终答案,最高位放在lastAns[0]
int getAns(){
int cur = 0;
while(ans[p3] >= 2){ //9
lastAns[cur++] = 9; ans[p3] -= 2;
}
while(ans[p2] >= 3){ //8
lastAns[cur++] = 8; ans[p2] -= 3;
}
while(ans[p7] >= 1){ //7.。。一次类推
lastAns[cur++] = 7; ans[p7] -= 1;
}
while(ans[p2]>=1 && ans[p3]>=1){
lastAns[cur
++] = 6; ans[p2]--; ans[p3]--;
}
while(ans[p5]>=1){
lastAns[cur
++] = 5; ans[p5]--;
}
while(ans[p2]>=2){
lastAns[cur
++] = 4; ans[p2] -= 2;
}
while(ans[p3]>=1){
lastAns[cur
++] = 3; ans[p3]--;
}
while(ans[p2]>=1){
lastAns[cur
++] = 2; ans[p2]--;
}
return cur;
}

int main(){
while(scanf("%s", cData)){
if(cData[0] == '-') return 0;
len
= strlen(cData);
if(len == 1){
printf(
"1%s\n", cData);
continue;
}

memset(data,
0, sizeof(data));
memset(ans,
0, sizeof(ans));
memset(lastAns,
0, sizeof(lastAns));
for(int i=0; i<len; i++){
data[i]
= cData[len - i -1] - '0';
}

if(!solve(data, 0, len)){
printf(
"There is no such number.\n");
}
else{
int iMax = getAns();
for(int i=iMax-1; i>=0; i--){
printf(
"%d", lastAns[i]);
}
printf(
"\n");
}
}

return 0;
}

________________________________________________________

[附]: 错误代码:


#include <cstdio>
#include
<cstring>
using namespace std;

const int maxN = 1000 + 5;
char cData[maxN];
int data[maxN], tmpAns[maxN], ans[maxN], len;
int lastAns[maxN];

/* 这时较完整版大整数除法。。本题用不上
int minus(int *a, int *b, int maxLen){
int ansLen;
for(int i=0; i<maxLen; i++){
a[i] = a[i] - b[i];
if(a[i] < 0){
a[i] += 10; a[i+1]--;
}
if(a[i]) ansLen = i + 1;
}
return ansLen;
}

bool inline getMax(int *a, int *b, int maxLen){
for(int i=maxLen-1; i>=0; i--){
if(a[i] > b[i]) return true;
else if(a[i] < b[i]) return false;
}
return true;
}


int operate(int *a, int i, int maxLen){
int ansLen = -1;
memset(tmpAns, 0, sizeof(int)*maxN);
if(maxLen == 1){
if(a[0] % i != 0) return 0;
else{
tmpAns[0] += a[0] / i;
memcpy(a, tmpAns, sizeof(int)*maxN);
return 1;
}
}
while(true){
if(maxLen == 1){
if(a[0] % i != 0) return 0;
else{
tmpAns[0] += a[0] / i;
memcpy(a, tmpAns, sizeof(int)*maxN);
return ansLen + 1;
}
}

int tmp[maxN] = {}, tmpLen;
if(a[maxLen-1] > i){
tmp[maxLen-1] = i;
tmpLen = maxLen - 1;
}
else{
tmp[maxLen-2] = i;
tmpLen = maxLen - 2;
}
if(ansLen == -1) ansLen = tmpLen;
int tmpMaxLen;
while(true){
tmpMaxLen = minus(a, tmp, maxLen);
tmpAns[tmpLen]++;
if(!getMax(a, tmp, maxLen)) break;
}
maxLen = tmpMaxLen;
}
}
*/

bool inline getMax(int *a, int *b, int maxLen){
for(int i=0; i<maxLen; i++){
if(a[i] > b[i]) return true;
else if(a[i] < b[i]) return false;
}
return false;
}

int inline operate(int *a, int i, int maxLen){
int ansLen = -1;
for(int j=maxLen-1; j>0; j--){
if(a[j] < i){
a[j
-1] += a[j]*10;
a[j]
= 0;
}
else{
a[j
-1] += (a[j] % i) * 10;
a[j]
= a[j] / i;
if(ansLen == -1) ansLen = j;
}
}
if(a[0] % i != 0) return 0;
else{
a[
0] = a[0] / i;
return (ansLen==-1 ? 1 : (ansLen+1));
}
}

bool solve(int *a, int maxLen, int lastNum, int ansLen){
if(maxLen == 1 && a[0] == 1){
// if(lastAns[0] == -1 || getMax(lastAns, ans, maxN))
// memcpy(lastAns, ans, sizeof(int)*maxN);
return true;
}

int tmpA[maxN], tmpLen = maxLen;
memcpy(tmpA, a,
sizeof(tmpA));
for(int i=lastNum; i<=9; i++){
if(ansLen > 0 && i * lastNum < 10) continue;
if(tmpA[0] % 2 != 0 && i % 2 == 0) continue;

int opAns = operate(tmpA, i, tmpLen);
if(!opAns){
memcpy(tmpA, a,
sizeof(tmpA));
continue;
}

ans[ansLen]
= i;

if(solve(tmpA, opAns, i, ansLen+1)) return true;
memcpy(tmpA, a,
sizeof(tmpA));
}
}

int main(){
while(scanf("%s", cData)){
if(cData[0] == '-') return 0;
len
= strlen(cData);
if(len == 1){
printf(
"1%c\n", cData[0]);
continue;
}

memset(data,
0, sizeof(data));
memset(ans,
0, sizeof(ans));
memset(lastAns,
0, sizeof(lastAns));
lastAns[
0] = -1;
for(int i=0; i<len; i++){
data[i]
= cData[len - i -1] - '0';
}

if(!solve(data, len, 2, 0)){
printf(
"There is no such number.\n");
}
else{
for(int i=0; ans[i]!=0; i++){
printf(
"%d", ans[i]);
}
printf(
"\n");
}

}


return 0;
}

posted on 2011-07-30 17:05  龙豆  阅读(706)  评论(0编辑  收藏  举报

导航