算法记录1

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;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值