解题思路:

思路一(优化前)
1.整个问题,当做售票员起初没有钱,然后孩子们的钱的面额为1 元,和2元,票价一元,问这些小孩共有多少种排队方法,使所有孩子买到票;
2.把孩子们的钱,放入数组A[]中,如题目两个一元,两个两元就是A[0]=1;  A[1]=1;  A[2]=2;  A[3]=2;

实现算法
void format(int *A,int N,int K)
{

  for(int i=0;i<(N+K);i++)
  {
    if(i<N)
    A[i]=1;
    else
    A[i]=2;
  }
    
  return;
}

3.把A[]进行全排列,每一种排列方式,判断一下,是否可以所有孩子都可以买到票;

4.判断方法,把售票员起初的钱 int num_of_yiyuan=0,设为0,遍历A[],当A[i]等于1时,num_of_yiyuan++,表示售票员有的

一元纸币的数目加1,当A[i]等于2时,要补钱,所以num_of_yiyuan--,表示售票员有的一元纸币数目减1;当num_of_yiyuan

为负数时,说明这种排队方式没办全买到票,就跳出循环;若循环正常结束,则num_of_yiyuan大于等于0,能全部买到票,满足的排队情况数目(sum)加1;

void panduan(int *A,int M,int *sum)
{
  int num_of_yiyuan=0;

  for(int i=0;i<M;i++)
   {
     if(A[i]==1)
      num_of_yiyuan++;
      else
      num_of_yiyuan--;

      if(num_of_yiyuan<0)
       break;
   }
  if(num_of_yiyuan>=0)
   (*sum)++;
return ;
}

 5.把判断函数加在全排列函数中即可

void pailie(int *A,int index,int length,int *sum)
{

   int i=0,j=0;

   if(index==length)
    {
     panduan(A,length,sum);
    }
    else
     for(j = index;j < length; j++)
        {
            swap(&A[j],&A[index]);
            pailie(A,index+1,length,sum);
            swap(&A[j],&A[index]);
        }
return ;
}


参考代码:

#include<stdio.h>
#include<malloc.h>
void format(int *A,int N,int K);  //把每个孩子的钱存入A[]
void pailie(int *A,int index,int length,int *sum);   //全排列函数
void swap(int *x,int *y);                          //用于全排列中交换两个数
void panduan(int *A,int M,int *sum);             //判断排队方式是否满足条件
int main()
{

 int M,N,K,sum=0;  //sum用于记录满足条件的排队情况数
 int *A;
 while( scanf("%d%d%d",&M,&N,&K)!=EOF)
 {
    sum=0;               //每次新数据置0
    A=(int *)malloc(M*sizeof(int));
    format(A,N,K);
    pailie(A,0,M,&sum);
    printf("%d\n",sum);
 }
return 0;
}

/*===================================================*/
void format(int *A,int N,int K)
{

  for(int i=0;i<(N+K);i++)
  {
    if(i<N)
    A[i]=1;
    else
    A[i]=2;
  }
    
  return;
}
/*===================================================*/
void pailie(int *A,int index,int length,int *sum)
{

   int i=0,j=0;

   if(index==length)
    {
     panduan(A,length,sum);
    }
    else
     for(j = index;j < length; j++)
        {
            swap(&A[j],&A[index]);
            pailie(A,index+1,length,sum);
            swap(&A[j],&A[index]);
        }
return ;
}

/*===================================================*/
void swap(int *x,int *y)
{
  int z=(*x);
  (*x)=(*y);
  (*y)=z;
return ;
}
/*===================================================*/
void panduan(int *A,int M,int *sum)
{
  int num_of_yiyuan=0;

  for(int i=0;i<M;i++)
   {
     if(A[i]==1)
      num_of_yiyuan++;
      else
      num_of_yiyuan--;

      if(num_of_yiyuan<0)
       break;
   }
  if(num_of_yiyuan>=0)
   (*sum)++;
return ;
}


2017-12-28 22-41-18屏幕截图.png

下面进行代码优化优化后时间从327 变为 38;

思路2(优化)

分析整个问题发现,第一个小孩的纸币面额必须要是1元,排队方式才有可能成立,所以,原问题变成M-1个人的全排列,又根据,两个拿一元零钱的小孩,他们的位置互换,也算是一种新的排法,所以我们把第一个拿一元钱的小孩分离出来,让剩下的小孩做排列,判断它们是否满足条件,最后把剩下小孩所做的排列所满足条件的数目乘以拿一元钱小孩的人数,就是成立的排队数;

注意:该思路售票员初始拥有的钱 int num_of_yiyuan=1为1;


#include<stdio.h>
#include<malloc.h>
void format(int *A,int N,int K);
void pailie(int *A,int index,int length,int *sum);
void swap(int *x,int *y);
void panduan(int *A,int M,int *sum);
int main()
{

 int M,N,K,sum=0;
 int *A;
 while( scanf("%d%d%d",&M,&N,&K)!=EOF)
 {
    sum=0;
    A=(int *)malloc((M-1)*sizeof(int));   //长度改为M-1
    format(A,N-1,K);                      //拿一元钱的孩子数减去1
    pailie(A,0,M-1,&sum);                 //长度改为M-1
    printf("%d\n",sum*N);               //排在第一个拿一元钱的孩子有N种情况,故结果有sum*(N)种
 }
return 0;
}

/*===================================================*/
void format(int *A,int N,int K)                  //此函数不变
{

  for(int i=0;i<(N+K);i++)
  {
    if(i<N)
    A[i]=1;
    else
    A[i]=2;
  }

  return;
}
/*===================================================*/
void pailie(int *A,int index,int length,int *sum)     //这个也不变
{

   int i=0,j=0;

   if(index==length)
    {
     panduan(A,length,sum);
    }
    else
     for(j = index;j < length; j++)
        {
            swap(&A[j],&A[index]);
            pailie(A,index+1,length,sum);
            swap(&A[j],&A[index]);
        }
return ;
}

/*===================================================*/
void swap(int *x,int *y)  //不变
{
  int z=(*x);
  (*x)=(*y);
  (*y)=z;
return ;
}
/*===================================================*/
void panduan(int *A,int M,int *sum)
{
  int num_of_yiyuan=1;               //售票员初始钱改为1

  for(int i=0;i<M;i++)
   {
     if(A[i]==1)
      num_of_yiyuan++;
      else
      num_of_yiyuan--;

      if(num_of_yiyuan<0)
       break;
   }
  if(num_of_yiyuan>=0)
   (*sum)++;
return ;
}

别忘点赞哦-.-

点赞(53)
 

0.0分

11 人评分

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

评论列表 共有 5 条评论

名字叫大梦一场 1年前 回复TA
@油专软工狗 长度和位置
油专软工狗 2年前 回复TA
length,index 是啥意思 看不懂, 嘤嘤嘤
九三 3年前 回复TA
牛逼,膜拜膜拜!!
20物联网3班刘帅甫 3年前 回复TA
@攻克飞上天 不是在pailie中调用了吗,一个函数可以被另一个函数调用
攻克飞上天 6年前 回复TA
Panduan函数没有在账号函数调用啊?