1.优美的立方质数
如果一个质数能被表示为三个不同的质数的和的形式,那么我们称它为立方质数。现在给你一个数n,判断它是不是立方质数。
输入数据
正整数n,n<=1000
输出数据
Yes或者No
样例输入
19
样例输出
Yes
思路
根据题目的要求,我们首先要判断输入的这个数是否是质数,我们可以设计一个名为prime的函数来判断一个数是否为质数,然后使用两层循环即可得到最终的结果。
#include <iostream>
#include <math.h>
using namespace std;
bool prime(int n);
int main()
{
int num;
cin>>num;
if(prime(num))//判断输入的数是否正确
{
cout<<"No"<<endl;
return 0
}
for(int i=2; i<1000; i++)
{
if(prime(i)==false)
continue;
for(int j=i+1; j<1000; j++)//由于题目说三个不同的质数,所以不用从头循环
{
if(prime(j) == false)
continue;
if(prime(num-i-j) && (num-i-j)!=i && (num-i-j) !=j)
{
cout<<"Yes"<<endl;
return 0;
}
}
}
cout<<"No"<<endl;
return 0;
}
bool prime(int n)
{
if(n<2)
{
return false;
}
for(int i=2; i<=sqrt(n);i++)//根据对称性,不需要全部循环;对于20而言,2和10是一对
{
if(n%i==0)
{
return false;
}
}
return true;
}
2. 课堂作业-6-2
我们有n根的木棍。现在从这些木棍中切割出来m条长度相同的木棍,问这m根木棍最长有多长?
输入数据
第一行输入两个数字,n(1<=n<=1000)为木棍数目,m(1<=m<=1000)为需要切割出的相同长度的木棍数目 随后n个正整数,表示原始木棍的长度(<=10000)
输出数据
每组输出一行结果,表示切割后绳子的最长长度(保留两位小数)
样例输入
4 5
5 6 7 8
样例输出
Yes
思路
我们可以使用二分查找的方式,根据题目给定的木棍的长度范围进行二分查找。每次都是用长度为(left+right)/2进行切分,判断切割出来的木棍数量是否大于m。如果小于m,说明用于切割的长度过长,应该减小切割的长度,即right应该改变大小;如果大于m,就继续判断有没有更大的切割长度,即left应该改变
#include <iostream>
using namespace std;
int cal(int *wood, double slide);//用于计算切割后,得到的木头数量是否达到m根,slide表示切割的长度,如果一根木头长为8,slide为4,则这个木头会被切为两个,每根长度为4
int n;
int m;
int main()
{
cin>>n;
cin>>m;
int wood[n];//wood数组表示木棍的长度
for(int i=0; i<n; i++)
{
cin>>wood[i];
}
double left=0;
double right=10000;//初始的边界
double Max = 0;
double mid;
while(right > left + 0.001)
{
mid = (left + right) / 2.0;
if(cal(wood, mid) >= m)
{
Max = mid;
left = mid;
}
else
{
right = mid;
}
}
printf("%.2f" , Max);
return 0;
}
int cal(int *wood, double slide)
{
int total = 0;
for(int i=0; i<n; i++)
{
total += wood[i] / slide;
}
return total;
}
3. 李老师的幸运数字
李老师的lucky number 是3,5和7,他爱屋及乌,还把所有质因数只有3,5,7的数字认定为lucky number,比如9, 15, 21, 25等等。请聪明的你帮忙算一算小于等于x的lucky number有多少个?
输入数据
一个正整数x,3=<x<=1000000000000
输出数据
小于等于x的lucky number的个数。
样例输入
49
样例输出
11
思路
由于输入数据过大,所以无法在规定的时间内全部便利判断。根据题目可知,我们所需要计算的数都是由若干个3,5,7这三个数相乘得到的。例如21=3 * 7,45=3 * 3 * 5,所以我们可以使用三重循环对3,5,7的个数进行遍历。
#include <iostream>
using namespace std;
int main()
{
int num;
cin>>num;
int total=-1;//因为第一次循环的结果是1,并不是我们所需要的,我们应该抛弃
for(int i=1; i<=num; i=i*7)//多乘一个7
{
for(int j=i; j<=num; j=j*5)//每循环一次就多乘一个5
{
for(int k=j; k<=num; k=k*3)//每循环一次就多乘一个3
{
total++;
}
}
}
return 0;
}
4.简单背包
李老师正准备暑假旅行,他有一个容量为L的行李箱和n个物品(n不超过20),每个物品都有自己的体积,物品可以放入行李箱,但行李箱中物品的总体积不能超过行李箱容量,李老师现在想知道他有多少种携带物品的方案(一个物品都不带也算一种方案)
输入数据
第一行为两个正整数n和L,分别代表物品总数和行李箱容量,n<=20,L<=1e9 接下来一行为n个正整数vi,代表第i个物品的体积,vi<=1e8
输出数据
方案数。
样例输入
3 10
2 4 5
样例输出
7
思路
由于每样物品只有拿和不拿两种选择,所以我们就会想到使用二叉树的思想来解决问题。
#include <iostream>
using namespace std;
void pick(int index, int v);//index表示一个物品的下标,每样物品都有不一样的下标,v代表背包所用的空间
int n, L;
int volume[20];//volume数组用来表示物品的体积
int total = 0;
int main()
{
cin>>n;
cin>>L;
for(int i=0; i<n; i++)
{
cin>>volume[i];
}
pick(0, 0);//初始时我们
cout<<total<<endl;
return 0;
}
void pick(int index, int v)
{
if(index == n)//如果物品编号到底了,我们退出递归
{
if(v <= L)//判断此时背包是否达到容量上限
{
total++;
}
return;
}
pick(index+1, v);//序号为index的物品不拿
pick(index+1, v+volume[index]);//序号为index的物品拿
}
5.课堂作业-7-2
有一条河,河中间有一些石头,已知石头的数量和相邻两块石头之间的距离。现在可以移除一些石头,问最多移除m块石头后(首尾两块石头不可以移除),相邻两块石头之间的距离的最小值最大是多少。
输入数据
第一行输入两个数字,n(2<=n<=1000)为石头的个数,m(0<=m<=n-2)为可移除的石头数目 随后n-1个数字,表示顺序和相邻两块石头的距离d(d<=1000)
输出数据
输出最小距离的最大值
样例输入
4 1
1 2 3
样例输出
3
#include <iostream>
#include <math.h>
using namespace std;
int num[1005]={0}, a[1005];
int n, m;
int check(int d)
{
int k = m;
int st = 1;
for (int end = 2; end <= n;)
{
int disCur = num[end] - num[st];
while (disCur < d)
{
k--;
end++;
if (k < 0)
return 0;
if(end > n)
{
if(st==1)
{
return 0;
}
else
{
return 1;
}
}
disCur = num[end] - num[st];
}
st = end;
end++;
}
return 1;
}
int main()
{
cin>>n;
cin>>m;
for(int i=2; i <= n; i++)
{
cin >> a[i];
num[i] = a[i]+num[i-1];
}
int left = 0, right = 1000 * 1000 + 5;
while (left < right)
{
int mid = (left + right) / 2 + 1;
if (check(mid))
left = mid;
else
right = mid - 1;
}
cout << left;
return 0;
}
6.数对选择
给你一个长度为n的数组和一个正整数k,问从数组中任选两个数使其和是k的倍数,有多少种选法。 对于数组a1=1 , a2=2 , a3=2而言:
(a1,a2)和(a2,a1)被认为是同一种选法;
(a1,a2)和(a1,a3)被认为是不同的选法。
输入数据
第一行有两个正整数n,k。n<=1000000,k<=1000000 第二行有n个正整数,每个数的大小不超过1e9
输出数据
选出一对数使其和是k的倍数的选法个数
样例输入
5 6
1 2 3 4 5
样例输出
2
思路
由于对一个数先相加再取余,和先取余再相加的结果是不改变的。利用这个特性,我们可以改良便利算法。我们可以设置k个数组,数组下标表示余数的大小,数组的内容表示余数相同的数据的个数。
#include <iostream>
using namespace std;
int n;
int k;
int group[1000000];
int main()
{
cin>>n;
cin>>k;
for(int i=0; i<k; i++)//其实可以不用循环,全局数组初始化为0
{
group[i] = 0;
}
for(int i=0; i<n; i++)
{
int num;
cin>>num;
group[num%k]++;//计算余数相同的数的数量
}
long long total=0;
for(int i=0; i<k; i++)//判断配对的组数
{
int j = (k-i) % k;
if(j<i)
{
break;
}
else if(j == i)
{
total += group[i] * (group[i]-1) / 2;
}
else
{
total += group[i] * group[j];
}
}
cout<<total<<endl;
return 0;
}