c/c++算法 基础题 练手汇总

因为是基础题所以都不算难,个人把碰见过的感觉比较好的练手基础题在这里做个汇总,方便查阅。

枚举

  • 一般都是数据量比较小的简单题,难点在于对数据的判断处理。用循环直接对数据区间枚举随后进行判断即可。如果数据量较大,就优化判断条件或者找共性减少运算时间。

1.安全区

题目描述
在一个nn的网格图上有m个探测器,第i个探测器位于(xi,yi)位置,探测半径为ri。
求出n
n个点中有多少个是安全的点,即未被探测的点。

输入
第一行为两个整数n,m(1<=n<=100,1<=m<=n*n)
接下来m行每行3个整数表示xi,yi,ri(1<=xi,yi,ri<=n)

输出
输出一个整数表示答案

样例输入
5 2
3 3 1
4 2 1

样例输出
17

OJ链接

思路: 重点是半径判断,我是用sqrt((x-x1) * (x-x1) + (y-y1) * (y-y1)) > r 来判断是否在检测半径内,同时用二维数组来储存是否能被探测到。

AC代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include<bits/stdc++.h>
using namespace std;

bool mymap[101][101];

void func(int x,int y,int r,int n)//中心点 x y 探测半径 r 地图总长 n
{
for(int a=x-r;a<=x+r;a++)
{
if(a<1||a>n)//x超界
continue;
for(int b=y-r;b<=y+r;b++)
{
if(b<1||b>n)//y超界
continue;
if(sqrt((x-a)*(x-a)+(y-b)*(y-b))>r)//不在半径内
continue;
//printf("%lf %d\n",sqrt((x-a)*(x-a)+(y-b)*(y-b)),r);
if(!mymap[a][b])
mymap[a][b]=true;
}
}
}

int main()
{
memset(mymap,false,sizeof(mymap));
int n,m,xi,yi,ri,ans=0;
cin>>n>>m;
/*for(int a=1;a<=n;a++)
{
for(int b=1;b<=n;b++)
{
printf("%d ",mymap[a][b]);
}
printf("\n");
}*/
for(int temp=0;temp<m;temp++)
{
cin>>xi>>yi>>ri;
func(xi,yi,ri,n);
}
for(int a=1;a<=n;a++)
{
for(int b=1;b<=n;b++)
{
//printf("%d ",mymap[a][b]);
if(mymap[a][b]==false)
ans++;
}
//printf("\n");
}
cout<<ans;
return 0;
}

2.统计方形

题目描述
有一个n*m方格的棋盘,求其方格包含多少正方形、长方形(此处长方形不包含正方形)

输入
输入存在多组测试数据。每组测试数据输入两个整数n,m,数字不超过5000

输出
对于每组数据输出一行包含两个整数,分别表示正方形数目和长方形数目

样例输入
2 3

样例输出
8 10

思路: 就是两层循环,代表当前图形的长和宽,长宽一样就是正方形,不一样就是长方形。然后求出这一行能有多少个这种图形(1+(m-b)),再求这一列有多少种这种图形(1+(n-a)),两者相乘就是这个图里有多少种这种图形。然后加到总数里,等循环跑完就是答案。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include<bits/stdc++.h>
using namespace std;

int main()
{
int n,m;
long long ans1=0,ans2=0;//ans1=正方形 ans2=长方形
cin>>n>>m;
for(int a=1;a<=n;a++)
{
for(int b=1;b<=m;b++)
{
if(a==b)
{
ans1+=(1+(n-a))*(1+(m-a));
}
else
{
ans2+=(1+(n-a))*(1+(m-b));
}
}
}
cout<<ans1<<" "<<ans2;
return 0;
}
  • 但是这样复杂度会比较高,可能会超时,所以有第二种求法。先求出总的矩形个数,再用一层循环求出正方形个数,总的减去正方形的就是长方形的。

AC代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <bits/stdc++.h>
using namespace std;

int main ()
{
/*对于一个n*m的棋盘,共有矩形 (m+m-1+m-2+...+1)*(n+n-1+n-2+...+1)
即[m*(m+1)/2]*[n*(n+1)/2]个,这一步可知用前一个式子循环道加,也可版用后一个式子直接算;
共有正方形(假设m>n) m*n+(m-1)*(n-1)+...+(m-n+1)*1 个,这步用循环做就行;
长方形就用 矩形权数 减去 正方形数 就行了。*/
int n,m;
while(scanf("%d %d",&n,&m)!=EOF)
{
long long sum1=0;
for(int i=1;i<=min(n,m);i++)
{
sum1+=(n-i+1)*(m-i+1);
}
printf("%lld ",sum1);
long long sum2=1LL*n*(n+1)/2*1LL*m*(m+1)/2;//1
printf("%lld\n",sum2-sum1);
}
return 0;
}

3.连续自然数和(尺取法)

题目
对于给定自然数N,求出存在多少个连续自然数段,长度至少为2,使得这些连续的自然数段之和为N。

输入
输入有若干行,每行一个正整数n。(1<=n<=2000000)

输出
对于每组测试数据输出第一个数字表示答案

样例输入
9
10000

样例输出
2
4

思路: 可以用for循环暴力循环出来,但是我下面是用的尺取法,来减少复杂度。

AC代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include<bits/stdc++.h>
using namespace std;

int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
int ans=0,temp=0,f=1,e=1;//答案个数 中间值 头 尾
while(n!=0)//尺取
{
while(temp<n&&e<n)
{
temp+=e;
e++;
}
if(temp<n)
{
break;
}
if(temp==n&&e-f>=1)
{
ans++;
}
temp-=f;
f++;
}
printf("%d\n",ans);
}
return 0;
}

4.蓝桥杯 数字分组

问题描述
  输入任意10个浮点数,根据它们的聚集程度划分为3组,输出每一组的平均值。
  提供老师上课讲的一种思路:将10个数字进行在数轴上排序,然后计算每两个点间的距离,在所有的距离中选取两个最大距离处断开,这样就把10个数字分为了3组。
  本题难度较大,如果深入讨论会比较复杂,大家可以只考虑如下面样例所示的分组情况非常简单的情况,只要简单情况能够成功计算,本题就能得分。
  另外,本题内容有些超前,推荐大家自学一下数组那一章中第一节一维数组,然后使用一维数组来做。排序算法可以参考trustie平台上传的冒泡排序法参考资料。

输入格式
  十个待输入的浮点数,使用空格隔开

输出格式
  三组数的平均数,每输出一个需要换行

样例输入
一个满足题目要求的输入范例。
例1:
50.4 51.3 52.3 9.5 10.4 11.6 19.1 20.8 21.9 49.6
例2:
8.6 7.4 3.5 17.9 19.1 18.5 37.6 40.4 38.5 40.0

样例输出
与上面的样例输入对应的输出。
例1:
10.5
20.6
50.9
例2:
6.5
18.5
39.125

思路: 直接循环枚举检测间隔即可。

AC代码: OJ链接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<bits/stdc++.h>
using namespace std;

double shuzu[10];
int main()
{
double max1=0,max2=0,m1,m2;
for(int a=0;a<10;a++)
{
scanf("%lf",&shuzu[a]);
}
sort(shuzu,shuzu+10);
for(int a=0;a<9;a++)
{
double temp=shuzu[a+1]-shuzu[a];
if(temp>max1)
{
max2=max1;
m2=m1;
max1=temp;
m1=a;
}
else if(temp>max2)
{
max2=temp;
m2=a;
}
}
double temp=0;
for(int a=0;a<=min(m1,m2);a++)
{
temp+=shuzu[a];
}
printf("%g\n",temp/(min(m1,m2)+1));
temp=0;
for(int a=min(m1,m2)+1;a<=max(m1,m2);a++)
{
temp+=shuzu[a];
}
printf("%g\n",temp/(max(m1,m2)-min(m1,m2)));
temp=0;
for(int a=max(m1,m2)+1;a<=9;a++)
{
temp+=shuzu[a];
}
printf("%g\n",temp/(9-max(m1,m2)));
return 0;
}