目录
一、函数题
1.二分查找
2. Iterative Mergesort
3.Quick Power
4.划分整数数组
二、编程题
1.古老的汉诺塔
2.士兵排队
3.输油管道问题
4.子序列的平均值
5.第k小元素
6.铺设油井管道
7.第k小
本题要求实现二分查找算法。
Position BinarySearch( List L, ElementType X );
其中List
结构定义如下:
typedef int Position; typedef struct LNode *List; struct LNode { ElementType Data[MAXSIZE]; Position Last; /* 保存线性表中最后一个元素的位置 */ };
L
是用户传入的一个线性表,其中ElementType
元素可以通过>、==、<进行比较,并且题目保证传入的数据是递增有序的。函数BinarySearch
要查找X
在Data
中的位置,即数组下标(注意:元素从下标1开始存储)。找到则返回下标,否则返回一个特殊的失败标记NotFound
。
Position BinarySearch( List L, ElementType X )
{
Position l=1,r=L->Last;
while(l>1;
if(L->Data[mid]>=X)r=mid;
else l=mid+1;
}
if(L->Data[l]==X)return l;
else return NotFound;
}
How would you implement mergesort without using recursion?
The idea of iterative mergesort is to start from N sorted sublists of length 1, and each time to merge a pair of adjacent sublists until one sorted list is obtained. You are supposed to implement the key function of merging.
void merge_pass( ElementType list[], ElementType sorted[], int N, int length );
The function merge_pass
performs one pass of the merge sort that merges adjacent pairs of sublists from list
into sorted
. N
is the number of elements in the list
and length
is the length of the sublists.
void merge_pass( ElementType list[], ElementType sorted[], int N, int length )
{
for(int i=0;iN)last=N;
while(num1
The function Power
calculates the exponential function Nk. But since the exponential function grows rapidly, you are supposed to return (Nk)%10007 instead.
int Power(int N, int k);
Both N
and k
are integers, which are no more than 2147483647.
int Power(int N, int k)
{
int res=1;
while(k)
{
if(k&1)res=(long long)res*N%10007;
k>>=1;
N=(long long)N*N%10007;
}
return res;
}
由n个正整数构成的集合A{ak}, 将其划分为两个不相交的子集A1,A2, 元素个数分别是n1,n2, A1和A2中的元素之和分别是S1,S2。
设计一个尽可能高效的划分算法,满足|n1-n2|最小,且|S1-S2|最大,返回|S1-S2|的结果。
注意:函数头已经给出,只需要写出函数体。
int Partition(int a[],int n); // 将数组a的整数集合划分成两个不相关子集,使得|n1-n2|最小,且|S1-S2|最大,返回|S1-S2|的结果。
int l=0,r=n-1,k=n/2;
int i=l,j=r;
while(1)
{
int x=a[i];
while(i=x)j--;
a[i]=a[j];
while(i
有三根A、B、C三根柱子,n个直径大小不同的圆盘,这些圆盘按照直径从大到小的次序从下到上放在A柱上,如果把1个圆盘从从一根柱子移动到另外一根柱子称作1次移动,在移动过程中允许借用B柱子,但不允许大圆盘放在小圆盘上面。现在要用最少的步数把这些圆盘全部移到C柱,请设计一个算法求出移动步骤和移动次数。
一个整数n(1≤n≤15),表示圆盘的个数。
输出移动盘子的过程和总的移动次数,先输出移动步骤,每一步占一行,格式为:当前要移动的盘子所在的柱子编号-->移动后所在柱子的编号。最后一行是总的移动次数。
#include
using namespace std;
int num=0;
void move(char first,char second)
{
cout<"<>n;
hanoi(n,'A','B','C');
cout<
在一个划分成网格的操场上,n个士兵散乱地站在网格点上。网格点用整数坐标(x,y)表示。士兵们可以沿网格边往上、下、左、右移动一步,但在同一时刻任一网格点上只能有一名士兵。按照军官的命令,士兵们要整齐地列成一个水平队列,即排列成(x,y),(x+1,y),…,(x+n-1,y)。如何选择x和y的值才能使士兵们以最少的总移动步数排成一行。
编程计算使所有士兵排成一行需要的最少移动步数。
题目引自POJ
第1行是士兵数n,1≤n≤10000。接下来n行是士兵的初始位置,每行有2个整数x和y,-10000≤x,y≤10000。
一个数据,即士兵排成一行需要的最少移动步数。
#include
using namespace std;
const int N=1e6+10;
int x[N],y[N];
int t,n;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d%d",&x[i],&y[i]);
sort(x+1,x+n+1);
for(int i=1;i<=n;i++)
x[i]-=i;
sort(x+1,x+n+1);
sort(y+1,y+n+1);
int resx,resy;
if(n%2)resx=x[n/2+1],resy=y[n/2+1];
else resx=(x[n/2+1]+x[n/2])/2,resy=(y[n/2+1]+y[n/2])/2;
long long ans=0;
for(int i=1;i<=n;i++)
ans+=abs(y[i]-resy)+abs(x[i]-resx);
cout<
某石油公司计划建造一条由东向西的主输油管道。该管道要穿过一个有n 口油井的油田。从每口油井都要有一条输油管道沿最短路经(或南或北)与主管道相连。如果给定n口油井的位置,即它们的x 坐标(东西向)和y 坐标(南北向),应如何确定主管道的最优位置,即使各油井到主管道之间的输油管道长度总和最小的位置? 证明可在线性时间内确定主管道的最优位置。
给定n口油井的位置, 计算各油井到主管道之间的输油管道最小长度总和。
输入的第1 行是油井数n,1<=n<=10000。接下来n 行是
油井的位置,每行2个用空格割开的整数 x和 y,-10000<=x,y<=10000。
输出油井到主管道之间的输油管道最小长度总和。
#include
using namespace std;
const int N=1e6+10;
int a[N];
int t,n;
int findk(int a[],int l,int r,int k)
{
if(l==r)
return a[l];
int i=l-1,j=r+1;
int x=a[l+r>>1];
while(ix);
if(i=k)findk(a,l,j,k);
else findk(a,j+1,r,k-p);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
int c;scanf("%d%d",&c,&a[i]);
}
int res=findk(a,1,n,n/2);
long long ans=0;
for(int i=1;i<=n;i++)
ans+=abs(a[i]-res);
cout<
给定一个长度为n的非负序列A,请你找出一个长度不小于L的子段(子段是序列A中一些连续的元素构成的集合),使得子段中数值的平均值最大。最终输出这个最大的平均值。
第一行两个整数n,L(1<=L<=n<=100,000)
以下n行,每行一个非负整数,表示序列A中每个元素的值。
一个整数,欲求的最大平均值乘以1000后的结果(注意不要四舍五入,直接输出)。
#include
using namespace std;
const int N=1e5+10;
double a[N],s[N];
int n,l;
bool check(double mid)
{
for(int i=1;i<=n;i++)s[i]=s[i-1]+a[i]-mid;
double mi=s[0];
for(int i=l;i<=n;i++)
{
mi=min(mi,s[i-l]);
if(s[i]-mi>=0)
return true;
}
return false;
}
int main()
{
cin>>n>>l;
double l=0,r=0;
for(int i=1;i<=n;i++)cin>>a[i],r=max(r,a[i]);
while(r-l>1e-6)
{
double mid=(l+r)/2;
if(check(mid))l=mid;
else r=mid;
}
printf("%d",(int)(r*1000));
}
给定一个大小为n(1≤n≤1000000)且无序的整型数组,数组中可能存在相同元素,请找出该数组第k(1≤k≤n)小的元素,注意这里的第k小元素指的是按从小到大排序后的第k个位置上的元素。
每个输入文件为一个测试用例,每个文件的第一行给出两个正整数n和k,第二行给出n个整数,其间以空格分隔。
输出第k小元素的值。
#include
using namespace std;
const int N=1e6+10;
int a[N];
int t,n;
int findk(int a[],int l,int r,int k)
{
if(l>=r)
return a[l];
int i=l-1,j=r+1;
int x=a[l+r>>1];
while(ix);
if(i=k)findk(a,l,j,k);
else findk(a,j+1,r,k-p);
}
int main()
{
int k;cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
cout<
某石油公司有n口油井,为方便输送石油,计划修建输油管道。根据设计要求,水平方向有一条主管道,每口油井修一条垂直方向的支线管道通向主管道。请设计一种算法确定主管道的位置,使得所有油井到主管道之间的支线管道长度的总和最小。提示:复杂度为O(n)才能通过所有测试用例。
每个输入文件为一个测试用例,每个文件的第一行给出一个正整数n(1≤n≤1000000),表示油井数量,从第二行起的n行数据,表示每口油井的位置,每行包含以空格分隔的两个整数,分别表示每口油井的横坐标x(−10000≤x≤10000)和纵坐标y(−10000≤y≤10000)。
输出各油井到主管道之间的支管道最小长度总和。
#include
using namespace std;
const int N=1e6+10;
int a[N];
int main()
{
int n;cin>>n;
for(int i=0;i<=n;i++)
{int c;scanf("%d%d",&c,&a[i]);}
sort(a,a+n);
int res=a[n/2];
long long ans=0;
for(int i=0;i
有n个数,求第k小的数。例如在数:{1 3 5 7 9 8 4 2 6 10}中,第3小的数是3 。
第一行输入两个数,n和k(n<=1000000),分别表示总的n个数和求第k小的数。第二行输入n个数( 最大数<10^7)。
一个数,表示第k小的数。
#include
using namespace std;
const int N=1e6+10;
int a[N];
int t,n;
int findk(int a[],int l,int r,int k)
{
if(l==r)
return a[l];
int i=l-1,j=r+1;
int x=a[l+r>>1];
while(ix);
if(i=k)findk(a,l,j,k);
else findk(a,j+1,r,k-p);
}
int main()
{
int k;cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
cout<