1.PostOffice
题目描述
在一个按照东西和南北方向划分成规整街区的城市里,n个居民点散乱地分布在不同的街区中。用x 坐标表示东西向,用y坐标表示南北向。各居民点的位置可以由坐标(x,y)表示。
街区中任意2 点(x1,y1)和(x2,y2)之间的距离可以用数值|x1-x2|+|y1-y2|度量。居民们希望在城市中选择建立邮局的最佳位置,使n个居民点到邮局的距离总和最小。
任务:给定n 个居民点的位置,编程计算n 个居民点到邮局的距离总和的最小值。
输入
第1 行是居民点数n,1 < = n < =10000。接下来n 行是居民点的位置,每行2 个整数x 和y,-10000 < =x,y < =10000。
输出
n 个居民点到邮局的距离总和的最小值。
样例输入
5 1 2 2 2 1 3 3 -2 3 3
样例输出
10
解题代码
#include<iostream>
#include<algorithm>
int x[10005], y[10005];
using namespace std;
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> x[i] >> y[i];
}
sort(x, x + n);
sort(y, y + n);
//注意点1:选取的最佳中心点为(x[n/2],y[n/2])
int sum = 0;
for (int i = 0; i < n; i++) {
//注意点2:abs()是求绝对值的函数
sum += abs(x[n / 2] - x[i]);
sum += abs(y[n / 2] - y[i]);
}
cout << sum << endl;
return 0;
}
2.最近对问题
标签:分治法
题目描述
设p1=(x1, y1), p2=(x2, y2), …, pn=(xn, yn)是平面上n个点构成的集合S,设计算法找出集合S中距离最近的点对。
输入
多组测试数据,第一行为测试数据组数n(0
输出
每组测试数据输出一行,为该组数据最近点的距离,保留4为小数。
样例输入
2 2 0 0 0 1 3 0 0 1 1 1 0
样例输出
1.0000 1.0000
解题代码(暴力法):
#include<iostream>
#include<math.h>
using namespace std;
//注意点1:数组不能开x[101]否则会造成runtime error运行错误
int x[1001],y[1001];
int main()
{
int n;
cin>>n;
while(n>0)
{
int m;
cin>>m;
for(int i=0;i<m;i++)
{
cin>>x[i]>>y[i];
}
//注意点2:这里用double不要用float
double minx=1e10;
for(int i=0;i<m-1;i++)
{
for(int j=i+1;j<m;j++)
{
//注意点3:这里求最小值不要用min()函数,会造成运行错误,而且不用加abs取绝对值,因为一个数的平方本来就是正数
int Cminx=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
if(Cminx<minx)
minx=Cminx;
}
}
//△注意点4:最后的结果要开方,因为是求距离
printf("%.4f\n",sqrt(minx));
n--;
}
return 0;
}
3.The Josephus Problem
题目描述
The problem is named after Flavius Josephus, a Jewish historian who participated in and chronicled the Jewish revolt of 66-70C.E. against the Romans. Josephus, as a general, managed to hold the fortress of Jotapata for 47days, but after the fall of the city he took refuge with 40 diehards in a nearby cave. There the rebels voted to perish rather than surrender. Josephus proposed that each man in turn should dispatch his neighbor, the order to be determined by casting lots. Josephus contrived to draw the last lot, and as one of the two surviving men in the cave, he prevailed upon his intended victim to surrender to the Romans. Your task:computint the position of the survivor when there are initially n people.
输入
a Positive Integer n is initially people. n< = 50000
输出
the position of the survivor
样例输入
6
样例输出
5
解题代码 法一:
理解:当人数为偶数时,我们可以将这些人分成两组,每组人数相同。在每一轮中,所有偶数编号的人会出列,这样每组中都会剩下人数减半的人。因此,我们可以通过计算n/2时的解来间接得到n时的解。
具体来说,假设有n个人,编号从1到n。在第一轮中,所有偶数编号的人(2, 4, 6, …, n)会出列,剩下的人的编号是1, 3, 5, …, n-1。这实际上是将原问题缩小为n/2个人(即1, 3, 5, …, n-1)的子问题。因此,我们可以通过计算n/2个人时的解来得到n个人时的解。
但是,由于编号的变化,我们需要对n/2时的解进行调整。在n/2个人时,最后留下的人的编号是J(n/2)。在n个人时,这个人在第一轮中的编号是2*J(n/2),因为在第一轮中,所有偶数编号的人都会出列,所以这个人的编号会减1。因此,n个人时最后留下的人的编号是2*J(n/2)-1。
#include<stdio.h>
#include<stdlib.h>
int J(int n){
//传递的参数是在场还活着的人的总数
if(n==1)
return 1;
else{
if (n%2==0){
n/=2;
return 2*J(n)-1;
}
else{
n=(n-1)/2;
return 2*J(n)+1;
}
}
}
int main(){
int n;
scanf("%d",&n);
int ans=J(n);
printf("%d\n",ans);
return 0;
}
解题代码 法二:
使用公式法
#include <stdio.h>
int main()
{
int n, m=2, i, s=0;
scanf("%d", &n);
//△注意点1:i<=n是可以取等的
for (i=2; i<=n; i++)s=(s+m)%i;
printf ("%d\n", s+1);
return 0;
}
4.实验四 俄式乘法
题目描述
俄式乘法,又被称为俄国农夫法,它是对两个正整数相乘的非主流算法。假设m和n是两个正整数,我们要计算它们的积。它的主要原理如下: if n is 偶数 n m=n/2 2m else n * m=(n-1)/2 + m 该算法只包括折半,加倍,相加等几个简单操作,因此实现速度非常快。具体计算如下图所示:

输入
两个正整数 n,m。
输出
n和m的乘积。 输出整个求和表达式,运算符与数字之间用一个空格隔开。
样例输入
50 65
样例输出
130 + 1040 + 2080 = 3250
解题代码:
#include<stdio.h>
int main()
{
int n, m,i=0;
int a[100];
scanf("%d%d",&n,&m);
//步骤一:记录不能整除的值,即要显示出来的值
while(n>0)
{
//△此处是%而不是/
if(n%2!=0)
{
a[i]=m;
i++;
}
n/=2;
m*=2;
}
int sum=0;
//步骤二:单独一个循环计算总和,即要显示的值相加,顺便将要显示的值打印出来
//注意点1:这里的i是继续增长后的i,相当于数组只有a[3],但是i=4
for(int j=0;j<i;j++)
{
sum+=a[j];
//△注意点2:在判断输入最后一个1的时候,a[i]已经记录了,但是i还是继续增加了,所以a数组实际的长度为i,但是i记录的长度为i+1
if(j==i-1)
printf("%d = ",a[j]);
else
printf("%d + ",a[j]);
}
printf("%d\n",sum);
return 0;
}
5.合并排序(mergesort)
题目描述
这是一个很简单的排序题目. 为了锻炼大家对不同算法的了解,请大家用归并排序法对此题进行解答. 对一组整数数列A[1],A[2],A[3]......A[N]进行排序,按照从小到大的顺序输出.
输入
本题只有一组测试数据,在输入的第一行输入N(表示整数数列的大小)(N < 1000) 接下来N行输入N个整数,每一行一个整数.
输出
对已经排好序的数从小到大依次输出,每两个数之间用两个空格隔开,且每输出10个数换行.
样例输入
12
45
545
48
47
44
45
4857
58
57
485
1255
42
样例输出
42 44 45 45 47 48 57 58 485 545
1255 4857
解题代码:
会出现PE错误,但是后面老师会判定为满分
#include<iostream>
using namespace std;
//注意点1:合并算法,注意brr,crr数组的长度取值
void merge(int *arr,int left,int middle,int right)
{
int brr[middle-left+1];
int crr[right-middle];
int begin1=0,begin2=0;
//注意点2:复制代码,i,j是可以取等的
for(int i=left;i<=middle;i++)
{
brr[begin1++]=arr[i];
}
//△此处的两边边界都是可以取等的
for(int j=middle+1;j<=right;j++)
{
crr[begin2++]=arr[j];
}
// 注意点1:start是从left开始的,因为合并排序区间:【left,right】
int begin3=0,begin4=0,start=left;
//△这里应该是&&而不是||,并且这里不能取等,因为begin1和begin2还在最后增加了1
while(begin3<begin1&&begin4<begin2)
{
if(brr[begin3]>crr[begin4])
{
arr[start]=crr[begin4];
begin4++;
start++;
}
else if(brr[begin3]<crr[begin4])
{
arr[start]=brr[begin3];
begin3++;
start++;
}
else
{
arr[start]=brr[begin3];
start++;
begin3++;
arr[start]=crr[begin4];
begin4++;
start++;
}
// 注意点4:说明brr数组还没比较完crr数组已经放完了,则brr数组里的数都大于crr
}
while(begin3<begin1)
{
arr[start]=brr[begin3++];
start++;
}
while(begin4<begin2)
{
arr[start]=crr[begin4++];
start++;
}
}
//注意点5:只划分,还没复制到另外的数组里
void mergesort(int *arr,int left,int right)
{
//△这里还需要再判断一下left<right,跟quicksort排序里一样,这是必须的,要不然会一直迭代下去不能停止
if(left<right)
{
int middle=left+(right-left)/2;
mergesort(arr,left,middle);
mergesort(arr,middle+1,right);
merge(arr,left,middle,right);
}
else
return ;
}
int main()
{
int n,arr[1001]={0},j=0;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>arr[i];
}
// 注意点6:这儿的右截止点是n-1
mergesort(arr,0,n-1);
for(j=0;j<n;j++)
{
cout<<arr[j]<<" ";
// △注意点7: 这里要写成(j+1)
if((j+1)%10==0){
cout<<endl;
}
}
return 0;
}
6.约瑟夫问题的实现
956: 约瑟夫问题的实现
题目描述
n个人围成一个圈,每个人分别标注为1、2、...、n,要求从1号从1开始报数,报到k的人出圈,接着下一个人又从1开始报数,如此循环,直到只剩最后一个人时,该人即为胜利者。例如当n=10,k=4时,依次出列的人分别为4、8、2、7、3、10,9、1、6、5,则5号位置的人为胜利者。给定n个人,请你编程计算出最后胜利者标号数。(要求用单循环链表完成。)
输入
第一行为人数n; 第二行为报数k。
输出
输出最后胜利者的标号数。
样例输入
10
4
样例输出
5
解题代码:
#include <stdio.h>
//n为总人数,m为第几个被杀,即杀人规则
int main()
{
//△这里的s要先定为0
int n, m, i, s=0;
scanf("%d %d", &n,&m);
//△这里的结束条件必须取等
for (i=2; i<=n; i++)
s=(s+m)%i;
printf ("%d", s+1);
return 0;
}
7.The Dutch flag problem
641: The Dutch flag problem
题目描述
The Dutch flag problem is to rearrange an array of characters R, W,and B (red, white, and blue are the colors of the Dutch national flag) so that all the R’s come first, the W’s come next, and the B’s come last. Design a linear in-place algorithm for this problem.
输入
two lines, the first line is total of numbers characters R,W and B ,and the numbers less than 500005 the second line is random characters R,W and B
输出
a line, all the R’s come first, the W’s come next, and the B’s come last.
样例输入
10
WRRWRWBBRW
样例输出
RRRRWWWWBB
解题代码:
法一:用划分算法,运用到三个指针left,mid,right
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
void dutch_flag_sort(char *arr, int n) {
int low = 0, mid = 0, high = n - 1;
//△此处应该是mid<high,而不是low<high,另外这里也可以取等
while (mid <= high) {
if (arr[mid] == 'R')
{
//注意点1:swap()是c++库中#include<algorithm>头文件下的std::swap,所以应该用using namespace std
swap(arr[mid],arr[low]);
low++;
mid++;
}
else if (arr[mid] == 'W')
{
mid++;
}
else
{ // arr[mid] == 'B'
swap(arr[mid],arr[high]);
high--;
}
}
}
int main() {
int n;
scanf("%d", &n);
char arr[n];
//注意点2:字符串的读取可以直接整段读取别忘了 Read the string without spaces
scanf("%s", arr);
dutch_flag_sort(arr, n);
printf("%s\n", arr);
return 0;
}
法二:巧办法:计数法
#include<iostream>
using namespace std;
int main()
{
int n;
cin>>n;
//注意点1:这里数组的取值不要定死了,要不然会出现runtime error
//解决办法一种是arr[n],另一种是用动态数组char *arr = new char[n+1],注意别忘了最后释放空间delete[] arr;
char arr[n];
cin>>arr;
int R=0,B=0,W=0;
for(int i=0;i<n;i++)
{
if(arr[i]=='R')
R++;
else if(arr[i]=='W')
W++;
else if(arr[i]=='B')
B++;
}
for(int i=0;i<R;i++)
cout<<'R';
for(int i=0;i<W;i++)
cout<<'W';
for(int i=0;i<B;i++)
cout<<'B';
cout<<endl;
return 0;
}
8.排列的字典序问题
标签:减治法
题目描述
n个元素{1,2,..., n }有n!个不同的排列。将这n!个排列按字典序排列,并编号为0,1,…,n!-1。每个排列的编号为其字典序值。例如,当n=3时,6 个不同排列的字典序值如下:
0 1 2 3 4 5
123 132 213 231 312 321
任务:给定n 以及n 个元素{1,2,..., n }的一个排列,计算出这个排列的字典序值,以及按字典序排列的下一个排列。
输入
第1 行是元素个数n(n < 15)。接下来的1 行是n个元素{1,2,..., n }的一个排列。
输出
第一行是字典序值,第2行是按字典序排列的下一个排列。
样例输入
8
2 6 4 5 8 1 7 3
样例输出
8227
2 6 4 5 8 3 1 7
解题代码
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int n;
cin>>n;
int arr[101],brr[101]={0};
for(int i=0;i<n;i++)
{
cin>>arr[i];
}
//找出每个元素后面有多少元素比它小的
for(int i=0;i<n-1;i++)
{
for(int j=i+1;j<n;j++)
{
if(arr[i]>arr[j])
{
brr[i]++;
}
}
}
//计算每一个brr[i]的阶乘和总的阶乘和sum
int mult,sum=0;
for(int i=0;i<n;i++)
{
mult=brr[i];
for(int j=1;j<n-i;j++)
{
mult*=j;
}
sum+=mult;
}
//输出
cout<<sum<<endl;
//△ 找出第一个违反升序的数,注意要写break
int index1;
for(int i=n-1;i>=0;i--)
{
if(arr[i-1]<arr[i])
{
index1=i-1;
break;
}
}
//逆序找到第一个比arr[index1]大的数
int index2;
for(int i=n-1;i>=0;i--)
{
if(arr[i]>arr[index1])
{
index2=i;
break;
}
}
//交换两个index表示的值
swap(arr[index1],arr[index2]);
//冒泡排序[index+1,n-1]包含的数
for(int i=index1+1;i<n-1;i++)
{
for(int j=i+1;j<n;j++)
{
if(arr[i]>arr[j])
{
swap(arr[i],arr[j]);
}
}
}
//输出
for(int i=0;i<n;i++)
{
cout<<arr[i]<<" ";
}
return 0;
}
9.The World Population Explosion(国名排序)
题目描述
In the past, when population grew, there was unexplored territory to inhabit. But now, almost all the habitable land has been explored. The world's population may reach 8.7 billion in 2033. It is clear that world population is a serious issue that needs careful attention. Human beings are unique to solve problems through cultural evolution. Facing the world population explosion in the near future, we must carry out the birth control program in order to save the mankind and save the world. And now we have the population amount of some country of the world in last year and this year. your task is to differ the countries whose population is changed from the data below and sort them in descending order and return the changing value and names of those countries whose population amount are not changed as well.
输入
The input consists of only one test case, followed by 4 lines, the first line is a integer N indicating the amount of the countries, and then input last year’s and this year’s population amount of every country in the last two lines before the names of the countries is inputted in the second line.
输出
You should output the countries firstly whose population are changed followed by the rest of those whose population are unchanged. If the changes are the same between two countries, lexicographic order should be used in your code.
样例输入
7
USA CHINA JAPAN KOREA CUBA ARGENTINA PERU
100 200 150 50 9 2 22
120 240 140 10 9 2 12
样例输出
40 CHINA
20 USA
-10 JAPAN
-10 PERU
-40 KOREA
0 ARGENTINA
0 CUBA
解题代码
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
typedef struct wp
{
char name[100];
int a,b,c;
} wp;
int main()
{
wp country[100];
int n,i,j;
scanf("%d",&n);
for(i=0; i<n; i++)
cin>>country[i].name;
for(i=0; i<n; i++)
cin>>country[i].a;
for(i=0; i<n; i++)
{
cin>>country[i].b;
country[i].c=country[i].b-country[i].a;
}
//注意点1:以下相当于一个冒泡排序,只是规则有变化
for(i=0; i<n-1; i++)
{
for(j=i+1; j<n; j++)
{
//△注意点2:这里注意只能是三个if,它是一个连续判断过程,不能写else if
if(country[i].c<country[j].c)//大的排前面
//△这里的交换是整体交换,是整个结构体进行交换
swap(country[i],country[j]);
if(country[i].c==0)//有0则换回来,负的排前面
swap(country[i],country[j]);
//注意点3:strcmp()是用于比较两个字符串的字典序排序,返回值若大于0,说明前者字典序大于后者,反之小于
if(country[i].c==country[j].c&&strcmp(country[i].name,country[j].name)>0)//相等,按字符的字典序排,字典序小的在前
swap(country[i],country[j]);
}
}
for(i=0; i<n; i++)
cout<<country[i].c<<" "<<country[i].name<<endl;
}
10.Quick sort
题目描述
Quicksort is a well-known sorting algorithm developed by C. A. R.
Hoare that, on average, makes Θ(n log n) comparisons to sort n items. However, in the worst case, it makes Θ(n2) comparisons. Typically, quicksort is significantly faster in practice than other Θ(n log n) algorithms, because its inner loop can be efficiently implemented on most architectures, and in most real-world data it is possible to make design choices which minimize the possibility of requiring quadratic time.
Quicksort sorts by employing a divide and conquer strategy to divide a list into two sub-lists.
The steps are:
1. Pick an element, called a pivot, from the list.
2. Reorder the list so that all elements which are less than the pivot come before the pivot and so that all elements greater than the pivot come after it (equal values can go either way). After this partitioning, the pivot is in its final position. This is called the partition operation.
3. Recursively sort the sub-list of lesser elements and the sub-list of greater elements. The base case of the recursion are lists of size zero or one, which are always sorted. The algorithm always terminates because it puts at least one element in its final place on each iteration (the loop invariant).
Quicksort in action on a list of random numbers. The horizontal lines are pivot values. Write a program to sort ascending int number by QuickSort ,n less than 50000.
输入
two lows, the first low is numbers , less and equal than 50000. the second low is a set integer numbers
输出
a set integer numbers of sort ascending
样例输入
10
4 2 1 5 7 6 9 8 0 3
样例输出
0 1 2 3 4 5 6 7 8 9
解题代码
注意:避免出现runtime error:应该使用了std::vector而不是数组:因为它提供了动态数组的功能,并且更容易处理边界情况。当使用数组时,需要手动管理数组的长度和边界,而std::vector则自动管理这些。(我有一篇博客详细讲解了快排https://blog.youkuaiyun.com/nineeeeeee/article/details/138783863?spm=1001.2014.3001.5501)
#include <iostream>
using namespace std;
#include "vector"
// 注意点1:注意使用要改变数组的值的话必须要使用&
void quickSortArr(vector<int> &arr, int begin ,int end) {
int l = begin;
int r = end;
//△注意点2:这里的判断语句是必须的,要不然这个迭代无法停止
if(l >= r) {
return;
}
int val = arr[l];
//注意点3:注意循环条件是可以取等的
while (l <= r) {
while (arr[r] > val) {
r--;
}
while (arr[l] < val) {
l++;
}
//△注意点4:交换之前也要判断一下,这里也是必须的,要不然顺序会乱
if(l<=r)
{
swap(arr[l],arr[r]);
l++;
r--;
}
}
//注意点5:注意左区间取值的右边界和右区间取值的左边界
quickSortArr(arr,begin,r); // 左
quickSortArr(arr,l,end); // 右
}
// 快速排序
int main() {
int n;
cin >> n;
vector<int> arr;
for (int i = 0; i < n; ++i) {
int a;
cin >> a;
//△必须写成这个样子,不能直接写输入arr[i]
arr.push_back(a);
}
quickSortArr(arr,0,n - 1);
//△这里可以改成i<n
for (int i = 0; i < arr.size(); ++i) {
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
11.Euclid's Game(欧几里得博弈)
题目描述
Starts with two unequal positive numbers (M,N and M>N) on the board. Two players move in turn. On each move, a player has to write on the board a positive number equal to the difference of two numbers already on the board; this number must be new, i.e., different from all the numbers already on the board. The player who cannot move loses the game. Should you choose to move first or second in this game?
According to the above rules, there are two players play tihs game. Assumptions A write a number on the board at first, then B write it.
Your task is write a program to judge the winner is A or B.
输入
Two unequal positive numbers M and N , M>N (M
输出
A or B
样例输入
3 1
样例输出
A
解题代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int main() {
int M, N, num;
cin>>M>>N;
//△这里的函数是双下划线!
num =M/__gcd(M,N);
//__gcd()是<algorithm>库中的函数,用来求两个数的最大公因数,还有另一个函数为gcd(),不过库中没有,需要用手敲,方法是欧几里得算法
//补充:int gcd(int a, int b){
// return b ? gcd(b, a % b) : a;
// }
// num=M/gcd(M,N);
//△这里的判断条件还要将num再%2来取余数
printf("%c\n", num % 2 ? 'A' : 'B');
return 0;
}
12.沙漠储油点
题目描述
一辆重型卡车预穿过长度大于1000公里小于1500公里的沙漠,卡车耗油为1升/公里,卡车总载油能力为500升。显然卡车装一次油是过不了沙漠的,因此司机必须设法在沿途建立几个储油点,使卡车能顺利穿越沙漠,试问司机如何建立这些储油点?每一个储油点应存多少汽油,才能使卡车以消耗最少汽油的代价通过沙漠? 请通过编程技术及 打印储油点的序号,各储油点距离沙漠始点的距离以及储油点的储油量.
输入
预穿过沙漠的长度公里整数Dis(大于1000公里小于1500公里).当输入0时程序结束.
输出
储油点序号 起始点到储油点的长度 储油点的储油量 ,这三个变量在一行中输出,每两个数据中有两个空格.并且这三个数据占一行.
样例输入
1000
1100
0
样例输出
1 25 3500
2 63 3000
3 108 2500
4 163 2000
5 234 1500
6 334 1000
7 500 500
1 14 5500
2 37 5000
3 63 4500
4 92 4000
5 125 3500
6 163 3000
7 208 2500
8 263 2000
9 334 1500
10 434 1000
11 600 500
解题代码
#include <iostream>
using namespace std;
int main()
{
int dis;
while(scanf("%d",&dis)!=EOF)
{
//步骤一:设置两数组存储石油数和距离
//定义两个数组a和b,分别用于存储每次往返后的剩余距离和累计消耗的油量。
int a[100]= {0},b[100]= {0};
//△ 注意除了dis其他的值都要放在数组循环中
int i=0,j=0,k=0;
while(dis>0)
{
dis=dis-500/(2*k+1);//往返次数为奇数次,2k+1
k++;
//△ 注意这里一定要用i,j分开,a[i]和b[i]不是某储油点相对应的长度距离和存油量
a[i++]=dis;//存长度
b[j++]=500*i; //存油量
}
//步骤二:逆序输出,注意起点和终点的取值
//△ i比真是数组长度多1,所以数组包含数字个数为i-1,但又是从0开始计数,所以还要再-1,即i-2;并且注意要取等
for(int j=i-2; j>=0; j--)
printf("%d %d %d\n",i-1-j,a[j],b[j]);
}
return 0;
}
13. 凸包面积
标签:分治法
题目描述
麦兜是个淘气的孩子。一天,他在玩钢笔的时候把墨水洒在了白色的墙上。再过一会,麦兜妈就要回来了,麦兜为了不让妈妈知道这件事情,就想用一个白色的凸多边形把墙上的墨点盖住。你能告诉麦兜最小需要面积多大的凸多边形才能把这些墨点盖住吗? 现在,给出了这些墨点的坐标,请帮助麦兜计算出覆盖这些墨点的最小凸多边形的面积。
输入
多组测试数据。第一行是一个整数T,表明一共有T组测试数据。 每组测试数据的第一行是一个正整数N(0< N < = 105),表明了墨点的数量。接下来的N行每行包含了两个整数Xi和Yi(0<=Xi,Yi<=2000),表示每个墨点的坐标。每行的坐标间可能包含多个空格。
输出
每行输出一组测试数据的结果,只需输出最小凸多边形的面积。面积是个实数,小数点后面保留一位即可,不需要多余的空格。
样例输入
2
4
0 0
1 0
0 1
1 1
2
0 0
0 1
样例输出
1.0
0.0
解题代码
#include<iostream>
#include<cmath>
#include<algorithm>
#include<stdio.h>
using namespace std;
int t,n;
struct node
{
int x,y;
}data[110],point[110],basic;
int direction(node pi,node pj,node pk)
{
return (pj.x-pi.x)*(pk.y-pi.y)-(pj.y-pi.y)*(pk.x-pi.x);
}
int dis(node a,node b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
int cmp(node pj,node pk)
{
int k=direction(basic,pj,pk);
if(k==0) return(dis(basic,pj)>dis(basic,pk));
else
return k>0?1:0;
}
int main()
{
cin>>t;
while(t--)
{
cin>>n; int flag=0;
for(int i=0;i<n;i++)
{
cin>>data[i].x>>data[i].y;
if(data[i].y<data[flag].y||(data[i].y==data[flag].y&&data[i].x<data[flag].x))
flag=i;
}
if(n<3)
{
cout<<"0.0\n"; continue;
}
node zz=data[0]; data[0]=data[flag]; data[flag]=zz;
basic=data[0];
sort(data+1,data+n,cmp);
int top=0;
point[top++]=data[0];
point[top++]=data[1];
point[top++]=data[2];
for(int i=3;i<n;i++)
{
while(direction(point[top-2],point[top-1],data[i])<0)
top--;
point[top++]=data[i];
}
double sum=0;
for(int i=1;i<top-1;i++)
sum+=abs(direction(point[0],point[i],point[i+1]));
printf("%.1lf\n",sum/2);
}
return 0;
}
14.翻煎饼
题目描述
麦兜最喜欢的食物是煎饼,每次在街上看到煎饼摊的时候都会在那里停留几分钟。最吸引麦兜还是煎饼师傅那一手熟练的翻煎饼的技术,一堆煎饼在那里,师傅只需要用铲子翻几下,就让煎饼整齐的叠在了一起。 这天,为了庆祝麦兜被保送上研究生,他从煎饼师傅那里买回来一些煎饼请客。但是麦兜买回的煎饼大小不一,麦兜太想吃煎饼了,他想吃这些煎饼中最大的那个。麦兜还知道同学们也很喜欢煎饼,为了表示他的诚意,他想让同学们先吃,麦兜最后吃,因此,麦兜想把煎饼按照从小到大的顺序叠放在一起,大的在最下面。这样麦兜就可以在最后拿到最大的那一块煎饼了。 现在请你帮助麦兜用煎饼师傅翻煎饼的方法把麦兜买的煎饼从小到大的叠在一起。煎饼师傅的方法是用铲子插入两块煎饼之间,然后将铲子上的煎饼翻一转,这样铲子上第一个煎饼就被翻到了顶上,而原来顶上的煎饼则被翻到了刚才插入铲子的地方。麦兜希望这样翻煎饼的次数最少。
输入
输入包括两行,第一行是一个整数n(1
输出
输出为一行,翻煎饼的最少次数
样例输入
5
5 4 2 3 1
样例输出
4
解题代码
#include<iostream>
#include<algorithm>
using namespace std;
int n,sum=0,a[1000];
int main()
{
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
while(n>1)
{
//△ 每查找一次最大值就要用一个新的最大值下标来代表
int maxn=0;
//△ 注意这里是用下标来比较,注意还可以取等的问题
for(int i=0;i<n;i++)
if(a[i]>=a[maxn]) maxn=i;
if(maxn==0)
{
sum+=1;
//注意交换函数的值
reverse(a,a+n);
}
else if(maxn!=n-1)
{
sum+=2;
reverse(a,a+maxn+1);
reverse(a,a+n);
}
n--;
}
cout<<sum<<endl;
}
15.数字模式的识别
标签:减治法
题目描述
数字的模式是指在一堆给定数字中出现次数最多的数值,如5,5,5,3,3,2,6,4,它的模式就是5。现在你的任务,就是从数字中找到它的模式.
输入
第一行为整数N.从第二行开始为N个整数。对于输入的每个数,有( |input_number|
输出
输出这些数字的模式,如果模式个数不为1,选择它们之中较小的。
样例输入
10
1 2 3 4 5 6 7 8 9 9
样例输出
9
解题代码
法一:
用unordered_map键值对的方法:
#include<iostream>
//△ 注意unordered_map的头文件的申请
#include<unordered_map>
using namespace std;
int main(){
int n;
cin>>n;
unordered_map<int,int>counts;
//△ 这里也是通过用下标来指代最大值
int maxn=0;
for(int i=0;i<n;i++)
{
int a;
cin>>a;
counts[a]++;
if(counts[a]>counts[maxn]||counts[a]==counts[maxn]&&a<maxn)
{
maxn=a;
}
}
cout<<maxn<<endl;
return 0;
}
法二:
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int n;
scanf("%d",&n);
int a[2000000]= {0}; //数组范围必要满足题目要求
for(int i=0; i<n; i++)
scanf("%d",&a[i]);
sort(a,a+n);//由小到大排列
int j=1,b=a[0],max=0,i;
for(i=1; i<n; i++)
{
if(a[i]==a[i-1])
j++;
else
{
if(max<j)
{
max=j;//记录最大的次数
b=a[i-1];//记录其值
}
j=1;//不相同重新开始计数
}
}
if(max < j)// 判断最后一个数的出现次数是否更大
{
max = j;
b=a[i];
}
printf("%d\n",b);
return 0;
}
16.变位词
标签:预排序
题目描述
如果两个单词的组成字母完全相同,只是字母的排列顺序不一样,则它们就是变位词,两个单词相同也被认为是变位词。如tea 与eat , nic 与cin, ddc与dcd, abc与abc 等。你的任务就是判断它们是否是变位词。
输入
第一行一个N,表示下面有N行测试数据。每行测试数据包括两个单词,如tea eat ,它们之间用空格割开
输出
对于每个测试数据,如果它们是变位词,输出Yes,否则输出No.
样例输入
3
tea eat
ddc cdd
dee dde
样例输出
Yes
Yes
No
解题代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
for(int k=0;k<n;k++)
{
int flag=0;
int a[26]={0};
int b[26]={0};
char str1[100],str2[100];
//scanf("%s",&str1);
cin>>str1;
for(int i=0;i<strlen(str1);i++)
{
a[str1[i]-'a']++;
}
cin>>str2;
for(int j=0;j<strlen(str2);j++)
{
b[str2[j]-'a']++;
}
for(int i=0;i<26;i++)
{
if(a[i]!=b[i])
{
flag=1;
}
}
if(flag==1)
printf("No\n");
else
printf("Yes\n");
}
return 0;
}
17.locker doors
题目描述
There are n lockers in a hallway numbered sequentially from 1 to n. Initially, all the locker doors are closed. You make n passes by the lockers, each time starting with locker #1. On the ith pass, i = 1, 2, ..., n, you toggle the door of every ith locker: if the door is closed, you open it, if it is open, you close it. For example, after the first pass every door is open; on the second pass you only toggle the even-numbered lockers (#2, #4, ...) so that after the second pass the even doors are closed and the odd ones are opened; the third time through you close the door of locker #3 (opened from the first pass), open the door of locker #6 (closed from the second pass), and so on. After the last pass, which locker doors are open and which are closed? How many of them are open? Your task is write a program to output How many doors are open after the last pass? Assumptions all doors are closed at first.
输入
a positive numbers n, total doors. n<=100000
输出
a positive numbers ,the total of doors opened after the last pass.
样例输入复制
10
样例输出复制
3
解题代码
#include<iostream>
#include<cmath>
using namespace std;
int main() {
int n,num=0;
cin >> n;
for (int i = 1;i<=n; ++i)
{
if(pow(i, 2) <= n)
num++;
}
cout << num <<endl;
return 0;
}
18: Binary search
标签:减治法
题目描述
A binary search algorithm (or binary chop) is a technique for finding a particular value in a sorted list. It makes progressively better guesses, and closes in on the sought value, by comparing an element halfway with what has been determined to be an element too low in the list and one too high in the list. A binary search finds the median element in a list, compares its value to the one you are searching for, and determines if it’s greater than, less than, or equal to the one you want. A guess that turns out to be too high becomes the new top of the list, and one too low the new bottom of the list. The binary search's next guess is halfway between the new list's top and bottom. Pursuing this strategy iteratively, it narrows the search by a factor 2 each time, and finds your value. A binary search is an example of a divide and conquer algorithm (more specifically a decrease and conquer algorithm) and a dichotomic search (more at Search algorithm). The most common application of binary search is to find a specific value in a sorted list. To cast this in the frame of the guessing game (see Example below), realize that we are now guessing the index, or numbered place, of the value in the list. This is useful because, given the index, other data structures will contain associated information. Suppose a data structure containing the classic collection of name, address, telephone number and so forth has been accumulated, and an array is prepared containing the names, numbered from one to N. A query might be: what is the telephone number for a given name X. To answer this the array would be searched and the index (if any) corresponding to that name determined, whereupon it would be used to report the associated telephone number and so forth. Appropriate provision must be made for the name not being in the list (typically by returning an index value of zero), indeed the question of interest might be only whether X is in the list or not. If the list of names is in sorted order, a binary search will find a given name with far fewer probes than the simple procedure of probing each name in the list, one after the other in a linear search, and the procedure is much simpler than organising a hash table though that would be faster still, typically averaging just over one probe. This applies for a uniform distribution of search items but if it is known that some few items are much more likely to be sought for than the majority then a linear search with the list ordered so that the most popular items are first may do better. The binary search begins by comparing the sought value X to the value in the middle of the list; because the values are sorted, it is clear whether the sought value would belong before or after that middle value, and the search then continues through the correct half in the same way. Only the sign of the difference is inspected: there is no attempt at an interpolation search based on the size of the differences. Your task is to write a program that, given a set numbers of ascending and a key, finding a particular postion in a sorted list.
输入
The input contains one total numbers(N<=5000000) and a find key,followed by a line containing the integer numbers ascending sets.
输出
if find the key in the sorted list, output containing postion in a sorted list, else ouput -1.
样例输入复制
10 7
0 1 2 3 4 5 6 7 8 9
样例输出复制
8
解题代码
二分查找
#include<iostream>
#include<algorithm>
using namespace std;
int arr[5000000];
int main()
{
int m,n;
cin>>m>>n;
for(int i=0;i<m;i++)
cin>>arr[i];
sort(arr,arr+m);
int left=0,right=m-1;
while(left<=right)
{
int middle=left+(right-left)/2;
if(arr[middle]>n)
right--;
else if(arr[middle]<n)
left++;
else
{
cout<<middle+1<<endl;
return 0;
}
}
cout<<-1<<endl;
return 0;
}
19: 堆排序
题目描述
堆排序(英语:Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
请你实现堆排序。
输入
两行,第1行是整数n
输出
升序排序结果。
样例输入复制
10
4 2 1 5 7 6 9 8 0 3
样例输出复制
0 1 2 3 4 5 6 7 8 9
解题代码
考试可暂时用快排来替代
#include <iostream>
using namespace std;
#include "vector"
// 注意点1:注意使用要改变数组的值的话必须要使用&
void quickSortArr(vector<int> &arr, int begin ,int end) {
int l = begin;
int r = end;
//注意点2:这里的判断语句是必须的
if(l >= r) {
return;
}
int val = arr[l];
//注意点3:注意循环条件是可以取等的
while (l <= r) {
while (arr[r] > val) {
r--;
}
while (arr[l] < val) {
l++;
}
//注意点4:交换之前也要判断一下
if(l<=r)
{
swap(arr[l],arr[r]);
l++;
r--;
}
}
//注意点5:注意左区间取值的右边界和右区间取值的左边界
quickSortArr(arr,begin,r); // 左
quickSortArr(arr,l,end); // 右
}
// 快速排序
int main() {
int n;
cin >> n;
vector<int> arr;
for (int i = 0; i < n; ++i) {
int a;
cin >> a;
arr.push_back(a);
}
quickSortArr(arr,0,n - 1);
for (int i = 0; i < arr.size(); ++i) {
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
20.校门外的树
题目描述
某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即0,1,2,……,L,都种有一棵树。由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。
输入
输入的第一行有两个整数L(1
输出
输出包括一行,这一行只包含一个整数,表示马路上剩余的树的数目。
样例输入复制
500 3
150 300
100 200
470 471
样例输出复制
298
解题代码
#include<stdio.h>
int main(){
int l,m,x,y,i,j,count;
// l,m表示马路长度和区域额数目
// x,y表示输入的区域的起点和终点
while(~scanf("%d%d",&l,&m))
{
count=0;
int a[10001]={0};
for(i=0;i<m;i++)
{
scanf("%d %d",&x,&y);
for(j=x;j<=y;j++)
{
a[j]=1;
}
}
for(i=0;i<=l;i++)
if(a[i]==0)
count++;
printf("%d\n",count);
}
return 0;
}
21.整数去重
1190: 整数去重
题目描述
给定含有n个整数的序列,要求对这个序列进行去重操作。所谓去重,是指对这个序列中每个重复出现的数,只保留该数第一次出现的位置,删除其余位置。
输入
多组测试数据; 对于每组数据: 输入包含两行; 第一行包含一个正整数n(1 <= n <= 20000),表示第二行序列中数字的个数; 第二行包含n个整数,整数之间以一个空格分开。每个整数大于等于10、小于等于100。
输出
每组数据输出只有一行,按照输入的顺序输出其中不重复的数字,整数之间用一个空格分开。
样例输入复制
5
10 12 93 12 75
样例输出复制
10 12 93 75
解题代码
#include<stdio.h>
using namespace std;
int main() {
int n;
while(~scanf("%d",&n))
{
//△ 注意点1:每次循环数组都要重新开始,所以数组用放置到while里面
int arr[105]={0},brr[20005];
for(int i=0;i<n;i++)
{
scanf("%d",&brr[i]);
if(arr[brr[i]]==0)
{
printf("%d ",brr[i]);
arr[brr[i]]++;
}
}
}
return 0;
}
22.花生采摘
348: 花生采摘
题目描述
鲁宾逊先生有一只宠物猴,名叫多多。这天,他们两个正沿着乡间小路散步,突然发现路边的告示牌上贴着一张小小的纸条:“欢迎免费品尝我种的花生!——熊字”。 鲁宾逊先生和多多都很开心,因为花生正是他们的最爱。在告示牌背后,路边真的有一块花生田,花生植株整齐地排列成矩形网格(如图1)。
有经验的多多一眼就能看出,每棵花生植株下的花生有多少。为了训练多多的算术,鲁宾逊先生说:“你先找出花生最多的植株,去采摘它的花生;然后再找出剩下的植株里花生最多的,去采摘它的花生;依此类推,不过你一定要在我限定的时间内回到路边。” 我们假定多多在每个单位时间内,可以做下列四件事情中的一件:
1) 从路边跳到最靠近路边(即第一行)的某棵花生植株;
2) 从一棵植株跳到前后左右与之相邻的另一棵植株;
3) 采摘一棵植株下的花生;
4) 从最靠近路边(即第一行)的某棵花生植株跳回路边。
现在给定一块花生田的大小和花生的分布,请问在限定时间内,多多最多可以采到多少个花生?注意可能只有部分植株下面长有花生,假设这些植株下的花生个数各不相同。
例如在图2所示的花生田里,只有位于(2, 5), (3, 7), (4, 2), (5, 4)的植株下长有花生,个数分别为13, 7, 15, 9。沿着图示的路线,多多在21个单位时间内,最多可以采到37个花生。

输入
输入的第一行包括三个整数,M, N和K,用空格隔开;表示花生田的大小为M * N(1
输出
输出包括一行,这一行只包含一个整数,即在限定时间内,多多最多可以采到花生的个数。
样例输入
6 7 21
0 0 0 0 0 0 0
0 0 0 0 13 0 0
0 0 0 0 0 0 7
0 15 0 0 0 0 0
0 0 0 9 0 0 0
0 0 0 0 0 0 0
样例输出
37
解题代码
#include <iostream>
#include<cmath>
#include<algorithm>
using namespace std;
//△ 步骤一:先建立花生点阵图,包含三要素,点的x,y坐标和花生数目,主要一定要大于500,否则会runtime error
struct peant
{
int row;
int line;
int amount;
} a[500];
//△ 步骤二:写sort排序法则,以结构体的花生数目为准则,结构体为类型重新定义两变量
bool cmp( peant x,peant y)
{
return x.amount<y.amount;
}
//△ 步骤三:写主函数main(),注意在此处已经给了时间了!后面就不要再定义time
int main()
{
int n,m,time,b,k=0;
scanf("%d%d%d",&n,&m,&time);
//步骤四:具体输入花生值来填充点阵图,注意x,y都是从1开始计数,左闭右闭区间
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
{
scanf("%d",&b);
if(b!=0)
{
a[k].row=i;//存行
a[k].line=j;//存列
a[k].amount=b;//存每株花生数
k++;
}
}
//△ 步骤五:排序并设置三要素:起点(为最后一株有值的花生处),采摘花生数,总时间,注意计算是从k-1开始的
sort(a,a+k,cmp);//从小到大排序
a[k].row=0,a[k].line=0;//存起点行,列
int sum=0;//采摘花生总数
time=time+a[k-1].line;//循环中多走了从k到k-1的横向点坐标值,因为真实有效的数据从大到小是从k开始的
//△ 步骤六:开始从后采摘花生,计算剩余时间,通过剩余时间能否返回第一行来判断是否加入总值
while(time>=0)
{
time=time-fabs(a[k-1].row-a[k].row)-fabs(a[k-1].line-a[k].line)-1;//从k株到达k-1株后,-1代表采摘时间,所剩时间
if(time<a[k-1].row)//k-1株时间不够回终点,该处花生采不到
break;
else
{
sum+=a[k-1].amount;
k--;//到下一株
}
}
//步骤七:输出采摘花生总数
printf("%d\n",sum);
return 0;
}
C语言题库.pdf



1万+






