鸽舍原理:也称"抽屉原理"或利克雷原则,它是一个重要而又基本的数学原理,应用它可以解决各种有趣的问题,并且常常能够得到令人惊奇的结果,许多看起来相当复杂,甚至无从下手的问题,利用它能很容易得到解决。
原理1:把n+1个元素分成n类,不管怎么分,则一定有一类中有2个或2个以上的元素。
原理2:把多于m×n个物体放到n个抽屉里,那么一定有一个抽屉里有m+1个或者m+1个以
上的物体。
原理2-1:把m个元素任意放入n(n<=m)个元素,则一定有一个集合至少有k个元素。
其中 k= [m/n]([]表示向上取整)。
(抽屉原理的一般含义为:"如果每个抽屉代表一个集合,每一个苹果就可以代表一个元素,假如有 n+1或多于n+1个元素放到n个集合中去,其中必定至少有一个集合里至少有两个元素。" )
-----
http://baike.baidu.com/view/9738418.htm
鸽舍原理求最大间隙:
问题描术:
最大间隙问题:给定n个实数x1,x2,……,xn,求这n个数在实轴上相邻2个数之间的最大差值。假设对任何实数的下取整方法耗时为O(1),设计解最大间隙问题的线性时间算法。
编程任务:
对于给定的n个实数x1,x2,……,xn。编程计算它们的最大间隙。
输入:
5
2.3 3.1 7.5 1.5 6.3
输出:
3.2
代码如下:
#include
#include
#include
#include
#include
#include //for memset()
#include //for floor()
#define _Print_ 0
using namespace std;
//打开文件,将数据保存到vector类型的vec中
template
int readfile(string filename, vector &vec)
{
ifstream ifile(filename.c_str(), ios_base::binary | ios_base::in);
if (!ifile)
{
cerr << "cannot open file!\n";
exit(1);
}
string str("");
getline(ifile, str);//第一行数据总个数,也可以直接统计vec长度
str = "";
while (getline(ifile, str))
{
size_t pos = 0;
size_t pos2 = 0;
while (pos2 <= str.size())
{
pos = str.find(' ', pos2);
if (pos != -1)
{
vec.push_back(atof(str.substr(pos2, pos - pos2).c_str()));
pos2 = ++pos;
}
else
{
vec.push_back(atof(str.substr(pos2).c_str()));
break;
}
}
}
return vec.size();
}
//打印vector模板中的元素
template
inline void printvec(vector &vec)
{
for (auto it = vec.begin(); it != vec.end(); ++it)
{
std::cout << *(it) << std::ends;
}
std::cout << std::endl;
}
//找到vector中最小值对应的下标
template
inline int getMinIndex(vector &vec)
{
int min_index = 0;
for (size_t index = 1; index < vec.size(); ++index)
{
if (vec[index] < vec[min_index])
{
min_index = index;
}
}
return min_index;
}
//找到vector中最大值对应的下标
template
inline int getMaxIndex(vector &vec)
{
int max_index = 0;
for (size_t index = 1; index < vec.size(); ++index)
{
if (vec[index] > vec[max_index])
{
max_index = index;
}
}
return max_index;
}
//获得最大间隙
template
T getMaxGap(int n,vector &vec)
{
typedef struct bucket
{
T low;
T high;
bool hasnum;
}bucket;
int max_index = getMaxIndex(vec);
int min_index = getMinIndex(vec);
T maxnum = vec[max_index];
T minnum = vec[min_index];
T buck_len = (maxnum - minnum)*1.0 / (n-1);
bucket* buck = new bucket[n - 1];
memset(buck, 0, (n - 1)*sizeof(bucket));
int buck_num(0);
//将n个元素每个元素放置到对应的桶内
buck[0].low = minnum; buck[0].high = minnum; buck[0].hasnum = true;
buck[n - 2].low = maxnum; buck[n - 2].high = maxnum; buck[n - 2].hasnum = true;
for (int i = 0; i < n; ++i)
{
if ((min_index == i) || (max_index == i))
continue;
//先判定元素是属于哪一个桶的,再确认其是不是桶内的最大或者最小元素
buck_num = floor((vec[i] - minnum) / buck_len);
if (false == buck[buck_num].hasnum)
{
buck[buck_num].high = vec[i];
buck[buck_num].low = vec[i];
buck[buck_num].hasnum = true;
}
else
{
if (vec[i]>buck[buck_num].high)
{
buck[buck_num].high = vec[i];
}
else if (vec[i] < buck[buck_num].low)
{
buck[buck_num].low = vec[i];
}
}
}
//在n-1个桶的边界找到最大间隔
T maxgap = 0;
T curgap=0;
int pre_index = 0; //上一个非空的桶的位置
for (int i = 1; i <= n - 2;++i)
{
if (buck[i].hasnum)
{
curgap = buck[i].low - buck[pre_index].high;
if (curgap > maxgap)
{
maxgap = curgap;
}
pre_index = i;
}
}
delete[] buck;
return maxgap;
}
//将数据写入output文件
template
inline int writefile(string filename, T n)
{
ofstream ofile(filename.c_str(), ios_base::binary | ios_base::out);
if (!ofile)
{
cerr << "cannot open file!\n";
exit(1);
}
ofile << n;
cout << "write over." << endl;
return 0;
}
int main()
{
string ifilename , ofilename;
vector vec;
cout << "input filename and ofilename:\n";
cin >> ifilename >> ofilename;
int n = readfile(ifilename, vec);
double maxgap = getMaxGap(n, vec);
writefile(ofilename, maxgap);
#if _Print_
{
printvec(vec);
cout << maxgap;
system("pause");
}
#endif
return 0;
}