关于N个鸡蛋放在M个篮子里等系列问题详解

2024-04-04 14:38

本文主要是介绍关于N个鸡蛋放在M个篮子里等系列问题详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

N > M。求出满足如下要求的所有鸡蛋方法。要求:1.篮子不能为空;2.对于任意正整数n<=N, 能取x个篮子,使篮子里的鸡蛋数总和等于n。

 

实现方法一:

#include <cstring>
#include <iostream>//namespace al{
int min(int x, int y)
{return x<=y?x:y;
}
void egg (int n, int m, int *&a,int size)
{ // n是鸡蛋数,m是篮子数,a数组用来存储结果,size是a数组的大小for (int i=min((n+1)/2, a[m]); i>=1; --i){if (n<m) {continue;}else if (n == m){for (int j=m-1; j>=0; --j){a[j] = 1;}m = 1;n = 0;}if (m == 1) {if (n > 1) {continue;}else{for (int k=0; k<size; ++k)std::cout<<a[k]<<" ";std::cout<<std::endl;return ;}} else {a[m-1] = i;egg (n-i, m-1, a, size);}}
}
//} //namespace alint main()
{int n=20;int m=10;int* a = new int[m];a[0] = 1;int *&aa = a;for (int i=(n+1)/2; i>=1; --i){ //由于egg函数中有i=min((n+1)/2, a[m])这句,所以数组最后一位是a[m-1],不存在a[m],所以这里初始处理下memset(a, 0, m);a[m-1] = i;//al::egg (n-i, m-1, aa, m);}
}

 

实现方法二:

#include <iostream>   
using namespace std;   
long pow2[20];   
int N,M;   
int ans[1000];   
void solve( int n , int m , int Min )   
{   if(n == N && m == M)   {   for(int i=0;i<M;i++)   {   cout<<ans[i]<<" ";         }    cout<<endl;   return ;         }    else if( n + (M-m)*Min > N || N > pow2[M-m]*n + pow2[M-m]-1)   return ;   else  {   for(int i = Min; i <= n+1; i++)   {   ans[m] =  i;       solve(n+i,m+1,i);    }                  }             
}     
int main()   
{   pow2[0] = 1;   for(int i=1;i<20;i++)   {   pow2[i] = pow2[i-1]<<1;          }   cin>>N>>M;   if( M > N || pow2[M]-1 < N)   {   cout<<"没有有效解"<<endl;               }          solve( 0 , 0 , 1 );   system("pause");       return 0;      
}  


说明:

1.n + (M-m)*Min > N 剪枝条件:放n个鸡蛋后,后面的篮子里即使都放Min个,总鸡蛋数都超过了N个。说明鸡蛋太少了
2.当前篮子放n个鸡蛋,下一个篮子放鸡蛋的个数为Min~n+1,也就是最多放n+1个,再下一个篮子最多放2n+2,4n+4...(n+1)*2^(M-m-1)
   当前篮子放n个,如果以后按最多的放,所有篮子的鸡蛋总和如果小于N,说明鸡蛋太多,放不完,要剪枝。即 
    n+(n+1)(2^0+2^1+2^2+2^3+...+2^(M-m-1))<N
    化简得:
    N > pow2[M-m]*n + pow2[M-m]-1

    此外main函数里的判断pow2[M]-1 < N也是按照这个思路推导的。

实现方法三:

#include <iostream>
using namespace std;#define MAX_M   32
int ar[ MAX_M + 1 ];
int egg = 9 , box = 5;void place_egg( int n , int m , int max )
{if( m == 1 ){ar[ 1 ] = n;for( int i = 1 ; i <= box ; i++ )cout << " " << ar[ i ];cout << endl;return;}if( m > n || n > ( 1 << m ) - 1 )return;if( ( n + 1 ) / 2 < max )max = ( n + 1 ) / 2;for( int i = max ; i >= ( n + m - 1 ) / m ; i-- ){ar[ m ] = i;place_egg( n - i , m - 1 , i );}
}int main()
{place_egg( egg , box , egg );return 0;
}


实现方法四:

/** * 假设 n>m 并且 n小于100 * @author Jason * 2011.3.30 */  
public class Test {  private int m;  private int n;  private int eggs[];  private int numAnswer;  Test(){  m=10;  n=20;  numAnswer=0;  eggs =  new int[m];  for(int i=0;i<m;i++){  eggs[i]=0;  }  }  private void fill(boolean [] state, int step, int sum){  if(step>=m){  state[sum] = true;  return ;  }  fill(state,step+1,sum);  fill(state,step+1,sum+eggs[step]);  }  /** * 判断是否满足:任意一个小于N的正整数,都能由某几个篮子内蛋的数量相加的和得到 * 算法:暴力枚举所有篮子的组合 * @return */  private boolean judge(){  boolean [] state = new boolean [n+1];  for(int i=0;i<=n;i++){  state[i] = false;  }  fill(state,0,0);  for(int i=1;i<=n;i++){  if(!state[i]){  return false;  }  }  return true;  }  /** * 给每个篮子分鸡蛋,升序(后一个篮子的鸡蛋必须不小于前一个篮子,避免重复计算) * @param pre 前一个篮子鸡蛋数 * @param already 前step个篮子 已使用的鸡蛋数 * @param step 第step个篮子 */  public void solve(int pre,int already, int step){  if(step==m-1){  //最后一个篮子   eggs[m-1]=n-already;  //不符合条件   if(eggs[m-1]<pre)    return;  //判断是否满足:任意一个小于N的正整数,都能由某几个篮子内蛋的数量相加的和得到   if(judge()) {  for(int i=0;i<m;i++){  System.out.print(eggs[i]+" ");  }  System.out.println();  numAnswer++;  }  return ;  }  // 给第step个篮子装鸡蛋,pre 到 n-already 种可能   for(int i=pre; i<=n-already; i++){  eggs[step]=i;  //递归   solve(i,already+i,step+1);  }  }  public static void main(String arg []  ){  Test test = new Test();  test.solve(1,0,0);  System.out.println("可能情况的数量:"+test.numAnswer);  }  
}  



 



这篇关于关于N个鸡蛋放在M个篮子里等系列问题详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/876056

相关文章

Java内存分配与JVM参数详解(推荐)

《Java内存分配与JVM参数详解(推荐)》本文详解JVM内存结构与参数调整,涵盖堆分代、元空间、GC选择及优化策略,帮助开发者提升性能、避免内存泄漏,本文给大家介绍Java内存分配与JVM参数详解,... 目录引言JVM内存结构JVM参数概述堆内存分配年轻代与老年代调整堆内存大小调整年轻代与老年代比例元空

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操

Python中注释使用方法举例详解

《Python中注释使用方法举例详解》在Python编程语言中注释是必不可少的一部分,它有助于提高代码的可读性和维护性,:本文主要介绍Python中注释使用方法的相关资料,需要的朋友可以参考下... 目录一、前言二、什么是注释?示例:三、单行注释语法:以 China编程# 开头,后面的内容为注释内容示例:示例:四

mysql表操作与查询功能详解

《mysql表操作与查询功能详解》本文系统讲解MySQL表操作与查询,涵盖创建、修改、复制表语法,基本查询结构及WHERE、GROUPBY等子句,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随... 目录01.表的操作1.1表操作概览1.2创建表1.3修改表1.4复制表02.基本查询操作2.1 SE

MySQL中的锁机制详解之全局锁,表级锁,行级锁

《MySQL中的锁机制详解之全局锁,表级锁,行级锁》MySQL锁机制通过全局、表级、行级锁控制并发,保障数据一致性与隔离性,全局锁适用于全库备份,表级锁适合读多写少场景,行级锁(InnoDB)实现高并... 目录一、锁机制基础:从并发问题到锁分类1.1 并发访问的三大问题1.2 锁的核心作用1.3 锁粒度分

MySQL数据库中ENUM的用法是什么详解

《MySQL数据库中ENUM的用法是什么详解》ENUM是一个字符串对象,用于指定一组预定义的值,并可在创建表时使用,下面:本文主要介绍MySQL数据库中ENUM的用法是什么的相关资料,文中通过代码... 目录mysql 中 ENUM 的用法一、ENUM 的定义与语法二、ENUM 的特点三、ENUM 的用法1

MySQL count()聚合函数详解

《MySQLcount()聚合函数详解》MySQL中的COUNT()函数,它是SQL中最常用的聚合函数之一,用于计算表中符合特定条件的行数,本文给大家介绍MySQLcount()聚合函数,感兴趣的朋... 目录核心功能语法形式重要特性与行为如何选择使用哪种形式?总结深入剖析一下 mysql 中的 COUNT

Redis出现中文乱码的问题及解决

《Redis出现中文乱码的问题及解决》:本文主要介绍Redis出现中文乱码的问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 问题的产生2China编程. 问题的解决redihttp://www.chinasem.cns数据进制问题的解决中文乱码问题解决总结

一文详解Git中分支本地和远程删除的方法

《一文详解Git中分支本地和远程删除的方法》在使用Git进行版本控制的过程中,我们会创建多个分支来进行不同功能的开发,这就容易涉及到如何正确地删除本地分支和远程分支,下面我们就来看看相关的实现方法吧... 目录技术背景实现步骤删除本地分支删除远程www.chinasem.cn分支同步删除信息到其他机器示例步骤

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁