| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 2366 人关注过本帖, 1 人收藏
标题:第二届“国信蓝点”杯全国软件专业人才设计与开发大赛 山东地区选拔赛 C语言 ...
只看楼主 加入收藏
qwermy
Rank: 3Rank: 3
等 级:论坛游侠
帖 子:34
专家分:160
注 册:2011-12-3
收藏
得分:0 
有点乱
#include <math.h>

int
main( void )
{
    int log_3( int n );
    int sum_n( int n );
    void prin( int n );
    int n;

    scanf( "%d", &n );
    while( n > 121)
    {
        scanf( "%d", &n );
    }

    printf("%d = ", n );
    prin( n );

    getch();

}

void
prin( int n )
{
    int i, sum, ok;

    i = log_3( n );
    sum = sum_n( i );
    if( n > sum )
    {
        printf( "%d", (int)pow( 3, i+1 ) );
        if( n % 3 == 1)
        {
        printf(" + 1");
        ok = pow( 3, i+1 ) - ( n - 1 );
            while( ok > 0 )
            {
            printf(" - %d", (int)pow( 3, log_3( ok ) ) );
            ok -= pow( 3, log_3( ok ) );
            }
            return ;
        }
        if( n % 3 == 2)
        {
            printf(" - 1 ");
            ok = pow( 3, i+1 ) - ( n + 1 );
            while( ok > 0 )
            {
            printf(" - %d", (int)pow( 3, log_3( ok ) ) );
            ok -= pow( 3, log_3( ok ) );
            }
            return ;
        }
        if( n % 3 == 0 )
        {
            ok = pow( 3, i+1 ) - n;
            while( ok > 0 )
            {
            printf(" - %d", (int)pow( 3, log_3( ok ) ) );
            ok -= pow( 3, log_3( ok ) );
            }
            return ;
        }
    }
    else
    {
        printf( "%d", (int)pow( 3, i ) );
        if( n % 3 == 1)
        {
        printf(" + 1");
        ok = ( n - 1 )-pow( 3, i );
            while( ok > 0 )
            {
            printf(" + %d", (int)pow( 3, log_3( ok ) ) );
            ok -= pow( 3, log_3( ok ) );
            }

            return ;
        }
        if( n % 3 == 2)
        {
            printf(" - 1 ");
            ok = ( n + 1 ) - pow( 3, i );;
            while( ok > 0 )
            {
            printf(" + %d", (int)pow( 3, log_3( ok ) ) );
            ok -= pow( 3, log_3( ok ) );
            }
            return ;
        }
        if( n % 3 == 0 )
        {
            ok = n - pow( 3, i );;
            while( ok > 0 )
            {
            printf(" + %d", (int)pow( 3, log_3( ok ) ) );
            ok -= pow( 3, log_3( ok ) );
            }
            return ;
        }

    }
}

int
log_3( int n )
{
    int x = 0;

    while( n /= 3 )
    {
        x++;
    }

    return x;
}

int
sum_n( int n )
{
    int sum = 0;

    while( n >= 0 )
    {
        sum += pow( 3, n );
        n --;
    }
    return sum;
}
2011-12-08 16:12
qwermy
Rank: 3Rank: 3
等 级:论坛游侠
帖 子:34
专家分:160
注 册:2011-12-3
收藏
得分:0 
输入数 n 先和 在3^(i)到3^(i+1)次方之间;
  设sum 为 3的0次方到i次方之和;
当 n > sum 时 n = 3^(i+1) - 用减法,  当n%3 == 1 和n%3 == 2时 用 先+或- 一个 1;   
设m,m = 3^(i+1) - (n +或- 1); m>0; m -= m的i次(类似前面的i); 直到 m == 0;
  当n < sum 时 n = 3^(i) + 用加法
同上      
2011-12-08 16:23
心灵百合
Rank: 5Rank: 5
等 级:职业侠客
帖 子:215
专家分:367
注 册:2011-3-30
收藏
得分:0 
还有没有漏掉的条件啊,只有这五个砝码吗
2011-12-08 17:21
hengde_li
Rank: 3Rank: 3
等 级:论坛游侠
帖 子:131
专家分:178
注 册:2010-1-15
收藏
得分:0 
回复 13楼 心灵百合
5个砝码够了,正因为这样,所以答案才是唯一的
2011-12-08 17:57
qwermy
Rank: 3Rank: 3
等 级:论坛游侠
帖 子:34
专家分:160
注 册:2011-12-3
收藏
得分:0 
感觉就是 把一个10进制表示成 两个三进制数,各个位只能用1 且两个数的同位不能同时为1 。
2011-12-08 18:59
sduwangpu
Rank: 1
等 级:新手上路
帖 子:1
专家分:0
注 册:2011-12-8
收藏
得分:0 
VC环境下编译的
/*  a  b  c  d  e 砝码  
    1  3  9  27 81 克
   五个砝码可得出几个数字:4=1+3,13=1+3+9,40=1+3+9+27,121=1+3+9+27+81
物体质量x=a[0]*e+b[0]*(a[1]*d+b[1]*(a[2]*c+b[2]*(a[3]*b+b[3]*a[4]*a)))
展开为x=a[0]e+b[0]a[1]d+b[0]b[1]a[2]c+b[0]b[1]b[2]a[3]b+b[0]b[1]b[2]b[3]a[4]a
 */
#include <stdio.h>
void main()
{
   int number,x;//number为输入的数
   int a[5]={0};//数组a表示5个砝码是否使用。0为不使用1为使用
   int b[4]={1,1,1,1};//数组b表示砝码在左或右。物体放在右,1为砝码在左,-1为砝码在右
   printf("please enter a number 1~121 :\n");
   scanf("%d",&number);
   x=number;
   if(x>40)//判断81克砝码是否使用
   {
       a[0]=1;//使用砝码
       x=x-81;//刨除改砝码质量,进入下一步if判断
       if(x<0)//判断数组b中元素的符号
       {
           x=-x;//将x变成正数
           b[0]=-1;
       }
   }
   if(x>13)//是否使用27克砝码
   {
       a[1]=1;
       x=x-27;
       if(x<0)//判断数组b中元素的符号
       {
           x=-x;
           b[1]=-1;
       }
   }
  if(x>4)//是否使用9克砝码
  {
      a[2]=1;
      x=x-9;
      if(x<0)//判断数组b中元素的符号
      {
          x=-x;
          b[2]=-1;
      }
  }
  if(x>1)//判断是否使用3克砝码
  {
      a[3]=1;
      x=x-3;
      if(x<0)//判断数组b中元素的符号
      {
          x=-x;
          b[3]=-1;
      }

  }
  if(x==1)//判断是否使用1克砝码
      a[4]=1;
  printf("%d=",number);//开始输出砝码组合
  if(a[0]!=0)//81克砝码
      printf("81g");
  if(a[1]!=0)//27克砝码
  {
      if(b[0]>0)
          printf("+27g");
      else
          printf("-27g");

  }
  if(a[2]!=0)//9克砝码
  {
      if(b[0]*b[1]>0)
          printf("+9g");
      else
          printf("-9g");

  }
  if(a[3]!=0)//3克砝码
  {
      if(b[0]*b[1]*b[2]>0)
           printf("+3g");
      else
           printf("-3g");

  }
  if(a[4]!=0)//1克砝码
  {
     if(b[0]*b[1]*b[2]*b[3]>0)
          printf("+1g");
      else
          printf("-1g");

  }
  printf("\n");
}
2011-12-08 21:24
czz5242199
Rank: 11Rank: 11Rank: 11Rank: 11
等 级:小飞侠
威 望:4
帖 子:660
专家分:2400
注 册:2011-10-26
收藏
得分:0 
这道题数据太小了没什么意思,我们不妨加强一下,改成给出n表示有n个砝码:3^0,3^1,3^2,....3^n-1,然后输入m(1<=m<=(3^n-1)/2),输出解决方案。

这个问题以前有一个简单一点的(给出2^0,2^1,2^2,2^n-1这n个砝码,给出m,输出如何组成m,这个问题的线性算法大家应该会)

现在的问题就是当变成3的阶乘时是可以做减法了而不局限于加法,二就是这个问题是不是也能在线性时间内解决。

对比上一个的解法类似,我们首先找到最小的p,使得3^p>=m(3^p是第p+1个砝码),然后有两个选择,到底是使用前p个砝码凑出m来还是用第p+1个砝码-(前p个砝码的某一个组合)凑出m来呢,在这里可以提出一个定律:就是给出的n个砝码一定可以凑出m(1<=m<=(3^n-1)/2)来,证明大家自己想,使用数学归纳法,证出来的话就知道前面这个问题怎么处理了。

大家最好自己写下程序,我这里提供一个参考:
程序代码:
#include <stdio.h>
#include <stdlib.h>

int three[20],n,m,i,j,flag[20]={0};

void dfs(int m,int dep,int fuhao)
{
     if (m==0) return;
     if (m>=three[dep])           //思考这里为什么m>=three[dep]就一定要取第dep个砝码
     {
                       flag[dep]=fuhao;
                       dfs(m-three[dep],dep-1,fuhao);
     }
     else if (m>=(three[dep]+1)/2)     //这个是怎么的出来的?
     {
                      flag[dep]=fuhao;
                      dfs(three[dep]-m,dep-1,-fuhao);
     }       
     else dfs(m,dep-1,fuhao);
}             

int main()
{
    scanf("%d%d",&n,&m);    //n个砝码,凑出m
    
    three[0]=1; for (i=1; i<n; i++) three[i]=three[i-1]*3;     //预处理出3的次方
    
    j=0; while (three[j]<m) j++;
    
    dfs(m,j,1);
    
    printf("%d=",m);
    for (i=j; i>=0; i--)
     if (flag[i])
     {
                 if (flag[i]==1) printf("+"); else printf("-");
                 printf("%d",three[i]);
     }
    printf("\n");
    
    system("pause");
    return 0;
}
     

表示程序好坏在于时间复杂度,这题如果直接枚举每个砝码的3种可能,就有3^n种可能,验证需要n时间,总得时间复杂度就是O(n*3^n),明显不是一个好算法,而上述程序的时间复杂度是O(n)

[ 本帖最后由 czz5242199 于 2011-12-8 22:45 编辑 ]
2011-12-08 22:42
hengde_li
Rank: 3Rank: 3
等 级:论坛游侠
帖 子:131
专家分:178
注 册:2010-1-15
收藏
得分:0 
show一下我写的代码,欢迎拍砖啊

#include <stdio.h>
#include <stdlib.h>

int near(int n, int *a, int num)
{
    int i, j, k=0, s=0;
    int * b=malloc(sizeof(int)*n);
    for (i=0; i<n; i++)
    {
        s+=a[i];
        b[i]=s;
    }
   
    for (i=1; i<n; i++)
        k=(num>b[i-1] && num<=b[i])?i:k;   
    free(b);
    return k;
}

int main(int argc, char *argv[])
{
    int i, j, num, a[5]={1,3,9,27,81};

    printf("please input the number less than 121 :  ");
    scanf("%d",&num);

    printf("\n the answer is : %d = ", num);   

    for (i=0; i<5; i++)
    {
        j = near(5,a,num);
        printf("%d ", a[j]);
        
        if (num < a[j])
        {
            printf(" - ");
            num = a[j]-num;
        }
        else if (num > a[j])
        {
            printf(" + ");
            num=num-a[j];
        }
        else
        {
            exit(0);
        }   
    }
   
    return 0;
}
2011-12-09 11:09
hengde_li
Rank: 3Rank: 3
等 级:论坛游侠
帖 子:131
专家分:178
注 册:2010-1-15
收藏
得分:0 
测试结果:

C:\>try
please input the number less than 121 :  55

 the answer is : 55 = 81  - 27  - 1
C:\>try
please input the number less than 121 :  78

 the answer is : 78 = 81  - 3
C:\>try
please input the number less than 121 :  40

 the answer is : 40 = 27  + 9  + 3  + 1
C:\>try
please input the number less than 121 :  41

 the answer is : 41 = 81  - 27  + 9  + 3  + 1
C:\>
2011-12-09 11:10
wenwen1314
Rank: 1
等 级:新手上路
帖 子:48
专家分:0
注 册:2011-9-25
收藏
得分:0 
你今年也参赛?    呵呵丶
                       我刚去吃饭了。  现在有个小想法。
                                    就是分别把定义这几个数为一个数组。
                                                {0,1,-1}
                                                {0,3,-3}
                                                                                                 {0,9,-9}
                                                                                                 {0,27,-27}
                                                                                                   {0,81,-81};
               然后执行for循环?  如果相等。。都输出。。   你觉得这个想法咋样?
2012-03-15 19:05
快速回复:第二届“国信蓝点”杯全国软件专业人才设计与开发大赛 山东地区选拔赛 ...
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.025054 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved