您的位置:首页 > 其它

淘宝实习生 笔试算法题 装鸡蛋

2011-04-01 13:34 211 查看
转自:http://blog.csdn.net/Jason20075563/archive/2011/03/30/6289267.aspx

在网上看到的第一批笔试里面的一个算法编程题。

问题:有N个蛋和M个篮子,把蛋放到M个篮子里,每个篮子都不能为空。另外,需要满足:任意一个小于N的正整数,都能由某几个篮子内蛋的数量相加的和得到。写出程序,使得输入一个(N,M),输出所有可能的分配情况。

自己写了一个下,纯暴力,几乎没剪枝。

当n为20,m为10的时候,结果是40中情况。

codes:

结果:

1 1 1 1 1 1 1 1 2 10

1 1 1 1 1 1 1 1 3 9

1 1 1 1 1 1 1 1 4 8

1 1 1 1 1 1 1 1 5 7

1 1 1 1 1 1 1 1 6 6

1 1 1 1 1 1 1 2 2 9

1 1 1 1 1 1 1 2 3 8

1 1 1 1 1 1 1 2 4 7

1 1 1 1 1 1 1 2 5 6

1 1 1 1 1 1 1 3 3 7

1 1 1 1 1 1 1 3 4 6

1 1 1 1 1 1 1 3 5 5

1 1 1 1 1 1 1 4 4 5

1 1 1 1 1 1 2 2 2 8

1 1 1 1 1 1 2 2 3 7

1 1 1 1 1 1 2 2 4 6

1 1 1 1 1 1 2 2 5 5

1 1 1 1 1 1 2 3 3 6

1 1 1 1 1 1 2 3 4 5

1 1 1 1 1 1 2 4 4 4

1 1 1 1 1 1 3 3 3 5

1 1 1 1 1 1 3 3 4 4

1 1 1 1 1 2 2 2 2 7

1 1 1 1 1 2 2 2 3 6

1 1 1 1 1 2 2 2 4 5
#include "stdafx.h"
#include<iostream>
#include<math.h>
#include<malloc.h>
#include<fstream>
using namespace std;
struct solution
{
int *ptr;
struct solution *next;
};
typedef struct solution solu;
int* first(int n,int m);  //计算出第一种组合
solu* others(int n,int m,solu *head,solu *prior);  //计算出其他组合
int sum(int n,int *p);  //计算前n-1个篮子里的蛋数和
bool only(solu *head,int *p,int m);  //检查组和是否满足要求
int ways;  //全局变量,保存组合的方法数
void main()
{
int n=0,m=0,i=0,k=0;
solu *head=NULL;
solu *temp=NULL;
LABLE:	cout<<"输入鸡蛋数N=";
cin>>n;
cout<<"输入篮子数M=";
cin>>m;
if(m<=0||n<=0||m>n||(double)n>=pow(2.0,m))  //对m,n的约束
{
cout<<"输入不合法!"<<endl;
goto LABLE;
}
cout<<"正在计算..."<<endl;
head=others(n,m,head,NULL);  //调用others开始计算
temp=head;
ofstream file("D://egg.txt");  //结果保存着这个目录下
cout<<"共有"<<ways<<"种组合方式:"<<endl;
file<<"共有"<<ways<<"种组合方式:"<<endl;
k=ways;
while(temp!=NULL&&ways)
{
cout<<"方式"<<k-ways+1<<":"<<endl;
file<<"方式"<<k-ways+1<<":"<<endl;
for(i=0;i<m;i++)
{
cout<<*(temp->ptr+i)<<" ";
file<<*(temp->ptr+i)<<" ";
}
delete[] temp->ptr;
temp=temp->next;
cout<<endl;
file<<endl;
ways--;
}
file.close();
cout<<"操作结果保存在D://egg.txt,您可以查看或删除之。";
cin>>i;
}
int sum(int n,int *p)  //计算前n-1个篮子里的总蛋数
{
int total=0;
for(int i=0;i<n;i++)
{
total+=*(p+i);
}
return total;
}
int* first(int n,int m)
{
int *p,i=0,temp1=0,temp2=0;
p=(int *)malloc(m*sizeof(int));
for(i=0;i<m;i++)   //每个篮子里放一个蛋
{
*(p+i)=1;
}
//下面的分配满足的条件:
//“总能找到几个篮子,使里面鸡蛋的和等于任意一个小于n的正整数”
//下面的if~else语句完成一种组合,升序排列,并使后面的篮里的蛋尽量多
if(n-m>m-1)
//剩下的蛋数大于前面m-1个篮子里的蛋数和,
{
*(p+m-1)+=m-1;
while(sum(m,p)<n)  //还有蛋剩余
{
temp1=n-sum(m,p);  //剩蛋数
for(i=m;i>0;)
{
temp2=sum(i-1,p);  //第i个篮子前面的所有篮子里的蛋数的总和
if(*(p+i-1)<=temp2)
//第i个篮子里的蛋数小于等于前面篮子里蛋的总数,给这个篮里加蛋
//否则,见else
{
if(temp1<=temp2-*(p+i-1)+1)  //剩下的蛋可以全部放到第i个篮里,完毕
{*(p+i-1)+=temp1;break;}
else {*(p+i-1)+=temp2-*(p+i-1)+1;break;}  //在第i个篮子放可能达到的最多蛋数
}
else i--;  //检测前面那个篮子
}
}
}
else *(p+m-1)+=n-m;
//剩下的蛋数小于等于前面m-1个篮子里的蛋数和,
//把所有的蛋都放到最后一个篮里,完成一种组合。
return p;

}
solu* others(int n,int m,solu* head,solu *prior)
{
int i=0,j=0,k=0;
if(head==NULL)  //还没有任何组合
{
solu *s=new(solu);
s->ptr=first(n,m);  //调用first()生成满足后面的值最大的升序序列
head=s;
head->next=NULL;
prior=head;
ways=1;
}
for(j=m-1;j>0;j--) //两重循环,开始计算其他组合
//原理是从后面的篮子里取出鸡蛋放入前面的篮子中
{
if(*(prior->ptr+j)==1)  //后面的篮子里蛋数为1,跳出循环
break;
for(i=j-1;i>0;i--)  //一个个往前挨
{
if(*(prior->ptr+j)-1>*(prior->ptr+i))   //后面的篮子减掉后不能比前面的少,保持升序排列
{
int *p=(int *)malloc(m*sizeof(int));
for(k=0;k<m;k++)
{
(*(p+k))=(*(prior->ptr+k));
}
(*(p+j))--;(*(p+i))++;
if(only(head,p,m))  //检查是否满足条件,满足则将结果添加到链表中
{
solu *stemp=new(solu);
stemp->ptr=p;
stemp->next=head->next;head->next=stemp;
head=others(n,m,head,stemp);
ways++;
}
else delete[] p;

}
else if(*(prior->ptr+j)-1==*(prior->ptr+i))
continue;
else
break;
}
}
return head;
}
bool only(solu *head,int *p,int m) //判断条件是否符合
{
solu *s=head;
int flag=0,i=0;
for(int k=0;k<m-1;k++)
{
if(*(p+k+1)<*(p+k)||*(p+k+1)>sum(k+1,p)+1)  //两个条件:1、升序,2、后面的数必须小于等于前面的篮子总数和加1
return false;
}
while(s!=NULL)  //判断是否有过相同的组合,有则返回false
{
flag=0;
for(i=0;i<m;i++)
{
if(*(s->ptr+i)!=*(p+i))
{
flag=1;
break;
}
}
if(!flag)
{
return false;
}
s=s->next;
}
return true;  //检查通过,返回true
}


1 1 1 1 1 2 2 3 3 5

1 1 1 1 1 2 2 3 4 4

1 1 1 1 1 2 3 3 3 4

1 1 1 1 1 3 3 3 3 3

1 1 1 1 2 2 2 2 2 6

1 1 1 1 2 2 2 2 3 5

1 1 1 1 2 2 2 2 4 4

1 1 1 1 2 2 2 3 3 4

1 1 1 1 2 2 3 3 3 3

1 1 1 2 2 2 2 2 2 5

1 1 1 2 2 2 2 2 3 4

1 1 1 2 2 2 2 3 3 3

1 1 2 2 2 2 2 2 2 4

1 1 2 2 2 2 2 2 3 3

1 2 2 2 2 2 2 2 2 3

可能情况的数量:40
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: