21位花朵数

花朵数是这么一个N位数,它的各个位数字的N次方之和为它的本身,比如:

1^3+5^3+3^3=153

现要求三分钟之内求解21位的水仙花数。

#include <stdio.h>
#include <memory.h>
#include <stdlib.h>
#include <sys/time.h>  

#define N 21
#define NUMBER_LENGTH_MAX 30

struct number
{
  char digits[NUMBER_LENGTH_MAX];
  int length;
};

struct counter
{
  int digits[10];
  int offset;
};

void assign(struct number *a, int b)
{
  a->length = 0;
  memset(&a->digits[0], 0, NUMBER_LENGTH_MAX);
  if (b == 0) a->length = 1;
  while(b > 0)
  {
    a->digits[a->length++] = b % 10;
    b /= 10;
  }
}

void copy(struct number *src, struct number *dst)
{
  dst->length = src->length;
  memcpy(&dst->digits[0], &src->digits[0], NUMBER_LENGTH_MAX);
}

void print(struct number *a)
{
  char *p = &(a->digits[0]);
  char *endp = &(a->digits[0]) + a->length;
  do
  {
    endp--;
    printf("%c", "0123456789"[(int)*endp]);
  }while(endp != p);
}

void add(struct number *a, struct number *b)
{
  int len = (a->length > b->length) ? a->length : b->length;
  int i;
  int carry = 0;
  int d;
  for (i = 0; i < len; i++)
  {
    d = (a->digits[i] + b->digits[i] + carry);
    a->digits[i] = d % 10;
    carry = d / 10;
  }
  if (carry > 0)
  {
    a->digits[len] = carry;
    len++;
  }
  a->length = len;
}

void mul(struct number *a, int b)
{
  int carry = 0;
  char *p = &(a->digits[0]);
  char *endp = &(a->digits[0]) + a->length;
  while(p != endp)
  {
    int d = carry + *p * b;
    *p = d % 10;
    carry = d / 10;
    p++;
  }
  if (carry > 0)
  {
    *p = carry;
    a->length++;
  }
}

int judge(struct counter *ctr, struct number *b, struct number *table)
{
  static struct number t;
  static int i;
  assign(b, 0);
  for (i = 9; i >= ctr->offset; i--)
  {
    if (ctr->digits[i] > 0)
    {
      copy(&table[(i * (N + 1)) + ctr->digits[i]], &t);
      add(b, &t);
    }
  }
  static struct counter new_ctr;
  memset(&new_ctr, 0, sizeof(new_ctr));
  new_ctr.offset = 0;
  char *p = b->digits;
  char *endp = b->digits + b->length;
  if (b->length != N) return 0;
  while (p != endp)
  {
    new_ctr.digits[(int)*p]++;
    p++;
  }
  for (i = 0; i < ctr->offset; i++)
  {
    if (new_ctr.digits[i] != 0) return 0;
  }
  for (i = ctr->offset + 1; i < 10; i++)
  {
    if (ctr->digits[i] != new_ctr.digits[i]) return 0;
  }
  return 1;
}

int iter(struct number *table)
{
  struct counter ctr;
  ctr.offset = 9;
  int remain = 0;
  ctr.digits[9] = N;
  while (1){
    if (remain == 0)
    {
      struct number sum;
      if (judge(&ctr, &sum, table))
      {
        print(&sum);printf("\n");
      }
      if (ctr.digits[ctr.offset] > 0)
      {
        ctr.digits[ctr.offset]--;
        remain++;
      }
      else
      {
        while (ctr.digits[ctr.offset] == 0) ctr.offset++;
      }
    }
    else
    {
      if (ctr.offset > 0)
      {
        ctr.offset--;
        ctr.digits[ctr.offset] = remain;
        remain = 0;
      }
      else
      {
        if (ctr.offset == 0 && remain == N) return 0;
        while (ctr.digits[ctr.offset] == 0) ctr.offset++;
        ctr.digits[ctr.offset]--;
        remain++;
      }
    }
  }
  return 0;
}

void init_table(struct number *table)
{
  int i, j;
  for (i = 0; i < 10; i++)
  {
    assign(&table[i * (N + 1)], 0);
    assign(&table[i * (N + 1) + 1], i);
    for (j = 0; j < N - 1; j++)
    {
      mul(&table[i * (N + 1) + 1], i);
    }
    for (j = 2; j <= N; j++)
    {
      copy(&table[i * (N + 1) + j - 1], &table[i * (N + 1) + j]);
      add(&table[i * (N + 1) + j], &table[i * (N + 1) + 1]);
    }
  }
}

int main(int argc, const char *argv[])
{
  struct number *table = (struct number *)malloc(sizeof(struct number) * ((N + 1) * 10));
  struct timeval time1, time2;
  gettimeofday(&time1, NULL);
  init_table(table);
  iter(table);
  free(table);
  gettimeofday(&time2, NULL);
  printf("time:%lu:%lu\n", time2.tv_sec - time1.tv_sec, time2.tv_usec - time1.tv_usec);
  return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值