首页 > 试题广场 >

车站建造问题

[编程题]车站建造问题
  • 热度指数:14361 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
X轴上10^8个点,从左到右依次编号为0~10^8-1,相邻点距离为1,其中有n个点有特殊意义,从小到大依次为a0~an-1,其中保证a0=0.
现在需要建设收集站,有两个要求必须被满足:
1、每个有意义的点必须修建收集站。
2、相邻收集站的距离必须为1或为某个质数。
现给出n和a数组,求需要建设收集站的最小数量。
示例1

输入

3,[0,7,11]

输出

4

说明

在0,7,8,11处建造收集站,差值分别为7,1,3,符合要求  

备注:
输入数据包含一个数n和一个长度为n的数组a,数组a的下标为0~n-1,保证a数组递增,且a0=0。
输出一个整数,表示答案。
1<=n<=1000,a数组中数值保证小于10^8
可以理解为将一个非质数表示为最少的质数和,分情况讨论:
1、当该非质数为偶数时,可以表示为两个质数的和(根据哥德巴赫猜想);
2、当该非质数为奇数时,分解为p=(p-2)+2:
        若p-2为质数,则可表示为两个质数的和
        若p-2为非质数,则可表示为三个质数的和(为什么,就是这么神奇!!!)

附上没有优化后的代码
    int work(int n, int* a, int aLen) {
        // write code here
        //就是一个寻找质数的问题
        int result=0;
        if(n==0||aLen==0)
            return result;
        for(int i=0;i<n-1;++i)
        {
            ++result;
            isOdd(a[i+1]-a[i],result);
        }
        ++result;
        return result;
    }
    void isOdd(int num,int &result){
        for(int i=2;i<=sqrt(num);++i)
        {
            if(num%i==0)//若不是质数
            {
                if(i==2)//若是偶数
                {
                    result+=1;
                    return;
                }
                else//若是奇数
                {
                    result+=1;
                    isOdd1(num-2,result);
                    return;
                }    
            }
        }
        
    }
     void isOdd1(int num,int &result){
        for(int i=2;i<=sqrt(num);++i)
        {
            if(num%i==0)//若不是质数
            {
                    result+=1;
                    return;
            }
        }
        
    }

发表于 2020-04-10 20:37:31 回复(3)
为啥这个提交是一串数据,一下子输入多行数据
发表于 2021-07-12 13:09:29 回复(1)

解题思路

根据题意,车站数最少是n,如果相邻两个车站的距离不是1或素数,就需要在中间插入一个或多个车站来使每个车站之间的距离都是1或素数,也就是求把一个非素数分解为素数的个数,可以想到哥德巴赫猜想。

维基百科:哥德巴赫猜想

对每个车站之间的距离进行判断,如果不是1或素数,就需要进行分解。如果距离是偶数,那么最多只需要新增一个车站;如果是奇数,最多需要新增两个车站,但也有只需要新增一个车站的例子,比如9=2+715=2+13。如果想把一个奇数分解为两个素数,就必须是一个奇素数、一个偶素数,偶素数只有2,所以先判断一下-2之后能不能得到素数,如果能,只需要新增1个车站;如果不能,那么由哥德巴赫猜想,-2之后的奇数也一定能分解成2个素数,所以需要新增 2个车站。

AC代码

class Solution {
public:
    /**
     * 
     * @param n int整型 
     * @param a int整型一维数组 
     * @param aLen int a数组长度
     * @return int整型
     */
    int work(int n, int* a, int aLen) {
        int count = n;
        for (int i = 1; i < n; i++) {
            int dist = a[i] - a[i - 1];
            if (dist != 1 && !isprime(dist)) {
                if (dist % 2 == 0 || isprime(dist - 2))
                    count += 1;
                else
                    count += 2;
            }
        }
        return count;
    }
private:
    bool isprime(int n) {
        if (n == 1)
            return false;
        for (int i = 2; i * i <= n; i++)
            if (n % i == 0)
                return false;
        return true;
    }
};
发表于 2020-07-02 15:39:19 回复(4)
这入门级。。我直接入土了。。
发表于 2020-06-22 21:27:11 回复(0)
判断OK就是是1或者质数,先判断OK不,OK就说明中间不用插入了,直接跳过。如果是偶数,那根据哥德巴赫猜想的欧拉版本,可以拆成2个质数,所以中间要插一个,如果是奇数,但是又能拆成2+质数的形式,那就也是插一个,否则根据哥德巴赫猜想的原始版本,这个普通的数能拆成三个质数的和,所以是插两个。
class Solution {
public:
    /**
     * 
     * @param n int整型 
     * @param a int整型一维数组 
     * @param aLen int a数组长度
     * @return int整型
     */
    int work(int n, int* a, int aLen) {
        int ans = n;
        for(int i=1;i<n;i++) {
            int val = a[i] - a[i-1];
            if(isOk(val)) {
                continue;
            }
            else if(!(val&1)) {
                ans += 1;
            }
            else if(isOk(val-2)) {
                ans += 1;
            }
            else {
                ans += 2;
            }
        }
        return ans;
    }
    
    bool isOk(int v) {
        if(v==1 || v==2)
            return true;
        for(int i=2;i*i<=v;i++) {
            if(v%i==0)
                return false;
        }
        return true;
    }
};




发表于 2020-07-18 12:04:04 回复(0)

这题居然用到了哥德巴赫猜想,真的秀到我了!
讲讲思路吧,首先每个牛牛所在村庄都要建一座车站,我们就将结果ret初始化为牛牛村庄的数量aLen。接下来就是计算每两个牛牛村庄之间的距离,如果为质数(或称素数),则不用在这两个村庄之间再修建车站;如果为非质数,就要分几种情况进行讨论(不妨设某两个村庄距离为为len):

  1. len为偶数,则可拆非为两个质数之和,意思就是在这两个村庄之间再修一座车站,ret++即可;
  2. len为奇数,则将将len拆分为len = (len - 2) + len,此时对于len-2,需要再分两种情况讨论:
    (i)len-2为质数,则len就是len-22两个质数之和,意思就是在这两个村庄之间再修一座车站,ret++即可;
    (ii)len-2为非质数,则可将len-2拆分成2个质数之和,进一步可将len拆分为3个质数之和,意思就是在这两个村庄之间再修两座车站,ret+=2即可。
    至于为什么会得到上面的结论,就请自行百度哥德巴赫猜想吧!QAQ
    代码就自己写吧,我的代码没有经过优化,就不放上来献丑了^^。
发表于 2020-06-11 23:12:57 回复(0)
//一开始使用贪心,错误,看了题解后才使用哥德巴赫猜想
class Solution {
private:
	int res;
public:
	int work(int n, int* a, int aLen) {
		res = 1;
		for (int i = 1; i < aLen; i++)
		{
			int distance = a[i] - a[i - 1];
			if (is_prime(distance))
				res++;
			else
			{
				if (distance % 2 == 0)
					res += 2;
				else
				{
					if (is_prime(distance - 2))
						res += 2;
					else
						res += 3;
				}
			}
		}
		return res;
	}

	bool is_prime(int n)
	{
		for (int i = 2; i <= sqrt(n); i++)
			if (n % i == 0)
				return false;
		return true;
	}
};

发表于 2020-04-18 20:07:11 回复(2)
9,[0,2,7,8,11,16,18,20,28]
为啥官方给的答案是 4,我就不怎么明白了,明明至少都是 9的啊??是我太菜了吗?
发表于 2020-07-28 17:29:40 回复(0)
首先说一下我对此题的一些困惑,n与aLen有什么区别?不都同时表示的是数组的长度的意思吗?= =
解题思路:
本题意思很简单,求解能建立多少个站点,我把问题转化为求站点之间的间距能拆分为多少组素数,站点数把最终的素数组数+1即可
对于本来就是素数的间距不需要处理,直接用isprime函数确定即可
而那些合数的间距num,怎么把他们拆分呢?其实这里我们不需要管怎么拆的,我们更关心的时能拆成多少份!那么这里有个直接的结论:
若num为偶数则可以拆成两个素数之和,
若num为奇数,若num-2为素数,则可以拆成两个素数之和,若为合数,则能可以拆成三个素数之和
    bool isprime(int num){
        if(num==1) return true;
        for(int i=2;i*i<=num;i++){
            if (num%i==0) return false;
        }
        return true;
    }
    int separate(int num) {
        if (isprime(num))        //判断是否为素数
            return 1;
        else
        {
            if (num % 2 == 0)    //判断是否为偶数
                return 2;
            else
            {
                if (isprime(num - 2))    //判断n-2是否为素数
                    return 2;
                else
                    return 3;
            }
        }
    }
    int work(int n, int* a, int aLen) {
        // write code here
        int ans =0;
        int length[2*n];
        for(int i=0;i<n-1;i++){
            length[i]=a[i+1]-a[i];
            if(isprime(length[i]))ans++;
            else ans += separate(length[i]);
        }
        return ans+1;
        
    }

发表于 2020-07-27 17:44:29 回复(0)
class Solution {
public:
    /**
     * 
     * @param n int整型 
     * @param a int整型一维数组 
     * @param aLen int a数组长度
     * @return int整型
     */
    isPrime(int x){
        for(int i=2;i*i<=n;i++)
            if(x%i==0)
                return false;
        return true;
    }
    int work(int n, int* a, int aLen) {
        int cnt = 1, d;
        for(int i=1;i<n;i++){
            d = a[i] - a[i-1];
            if(isPrime(d))
                cnt++;
            else{
                if(d&1){
                    if(isPrime(d-2))
                        cnt += 2;
                    else
                        cnt += 3;
                }else
                    cnt += 2;
            }
        }
        return cnt;
    }
};

发表于 2020-07-12 21:09:40 回复(0)
import java.util.*;


public class Solution {
    /**
     * 
     * @param n int整型 
     * @param a int整型一维数组 
     * @return int整型
     */
    public int work (int n, int[] a) {
        int count = 1,len = 0;
        for(int i=1; i<a.length; i++) {
            len = a[i] - a[i-1];
            if(isPrime(len)) {
                count++;
            } else if(len % 2 == 0 || isPrime(len-2)) {
                count += 2;
            } else {
                count += 3;
            }
        }
        return count;
    }
    
    private boolean isPrime(int num) {
        for(int i=2; i * i <= num; i++) {
            if(num % i == 0) {
                return false;
            }
        }
        return true;
    }
}

发表于 2020-06-09 02:17:35 回复(0)
这要不知道这个理论,怎么都是超时!
发表于 2020-04-15 20:21:43 回复(0)
我就说这个题目怎么都不算是入门级的难度,原来如此
发表于 2020-08-01 21:18:06 回复(0)
  1. 首先所有Ai均有车站,接下来判断距离是否为质数或1,是则车站数+1,否则继续判断距离;

  2. 当距离为偶数时,可以表示为两个质数的和(根据哥德巴赫猜想);

  3. 当距离为奇数时,分解为p=(p-2)+2:

若p-2为质数,则可表示为两个质数的和
若p-2为非质数,则可表示为三个质数的和

class Solution:

    def work(self , n , a ):
        # write code here
        count = n
        dis = [(i-j)for i,j in zip(a[1:],a)]
        for i in dis:
            if( i!=1 and self.isPrimeNumber(i)==False):
                if(i%2==0 or self.isPrimeNumber(i-2)):
                    count+=1
                else:
                    count+=2
        return count

    def isPrimeNumber(self,x):
        flag = True
        if(x==1):
            flag = False
        for i in range(2,int(x)):
            if(x%i==0):
                flag=False
                break
        return flag
发表于 2020-07-27 15:46:46 回复(0)
我感觉我的输出没问题
用例:
8,[0,1,4,11,12,21,22,29]
对应输出应该为:
9
你的输出为:
10 
[0, 1, 3, 7, 1, 7, 1, 1, 1, 7]
发表于 2020-07-24 19:12:59 回复(0)
抱着秒ac的心态,然后直接入土+1
发表于 2020-07-23 17:34:58 回复(0)
class Solution {
public:
    /**
    任一大于2的偶数都可写成两个质数(素数)之和
    任一大于5的整数都可写成三个质数(素数)之和

    首先建立n个车站(牛牛所在村庄)
    然后判断两个车站的距离dis是不是素数,
    如果是素数,两个车站之间不用再增加车站;
    如果dis不是素数,分两种情况(偶数和奇数);
        如果dis是偶数(此时dis大于2),有任一大于2的偶数可以写成两个素数之和,所以在两个车站之间再增加一个车站即可;
        如果dis是奇数,奇数 = 奇数 + 偶数,。有任一大于5的整数都可写成三个质数(素数)之和,有2即是偶数又是素数,
            如果dis-2是素数,那么说明dis = 素数 + 2(素数),此时只用增加一座车站即可:n + 1;
            如果dis-2不是素数,有任一大于5的整数都可写成三个质数(素数)之和,知只要在两个车站之间建立两个车站即可:n + 2
    **/
    int isPrime(int number)
    {
        if (number==1||number==2)
        {
            return 1;
        }else
        {
            for (int i=2; i<=number/2; i++)
            {
                if(number % i == 0)
                {
                    return 0; //不是素数
                }
            }
        }

        return 1;  //是素数
    }
    /**
     * @param n int整型 
     * @param a int整型一维数组 
     * @param aLen int a数组长度
     * @return int整型
     */
    int work(int n, int* a, int aLen) {
        // write code here
        for (int i=0; i<aLen-1; i++)
        {
            if (isPrime(a[i+1] - a[i])==1)
            {
                continue;
            }else
            {
                if((a[i+1] - a[i])%2 == 0)
                {
                    n += 1;
                }else
                {
                    if(isPrime(a[i+1] - a[i] - 2)==1)
                    {
                        n += 1;
                    }else
                    {
                        n += 2;
                    }
                }
            }
        }
        return n;
    }
};
发表于 2020-07-23 16:43:27 回复(0)
首先判断的是两个村庄之间的距离,继续判断该距离是不是偶数,如果是偶数,则将其可以分解为两个质数之和,因此,两个村之间只需要建一个就可以了,如果是奇数,可将其进行分解为len=(len-2)+len,继续得到len-2为质数,则len就是len-22两个质数之和,意思就是在这两个村庄之间再修一座车站,ret++即可;否则将在两者之间建两个火车站。(哥德巴赫的猜想)
发表于 2020-07-14 18:44:16 回复(0)
import java.util.*;
import java.math.*;

public class Solution {
/**
 哥德巴赫猜想: 1、大于2的偶数,可以表示为两个质数的和; 
 2、任一大于7的奇数都可写成三个质数之和。 
eg:当该非质数为奇数时,分解为p=(p-2)+2: 
p-2为质数,则该数可表示为两个质数的和 
p-2为非质数,则该数可表示为三个质数的和 */
* @param n int整型
* @param a int整型一维数组
* @return int整型
*/
public int work(int n, int[] arr) {
int result = 1;
for (int i = 0; i < n - 1; i++) {
int temp = arr[i+1] - arr[i];
if (isPrime(temp)) {
result += 1;
}
else if (temp % 2 == 0) {
result += 2;
}
else if (isPrime(temp - 2)) {
result += 2;
}
else {
result += 3;
}
}
return result;
}
//calculate prime
public boolean isPrime(int n) {
for (int i = 2; i <= Math.sqrt(n); i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
//main
public static void main(String args[]) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = scan.nextInt();
}
Solution solution = new Solution();
int result = solution.work(n,arr);
System.out.println(result);
}
}
编辑于 2020-06-20 11:17:10 回复(0)
public int work (int n, int[] a) {
        int c=0;
        for(int i=0; i<n-1; i++) {
            c+=getNum(a[i+1]-a[i]);
        }
        return n + c;
    }
    
    private int getNum (int len) {
        if(isPrime(len)) {    //两站间距是质数,不用在中间修站点
            return 0;
        } else {
            if(len%2 == 0) {    //两站间距非质数,是偶数,根据哥德巴赫猜想,大于2的偶数可写成两质数之和
                return 1;
            } else {
                if(isPrime(len-2)) {    //因为2是唯一的偶数质数,所以任一奇数不可能拆分为两个非2的质数相加
                                        //两站间距非质数,是奇数,想要中间只修一个站,只有拆分为2+(len-2)
                    return 1;
                }
                return 2;    //两站间距非质数,是奇数,且间距大于5(len=1,2,3,4,5都到不了这里)
                             //根据强哥德巴赫猜想,任一大于5的奇数都可写成三个质数之和
                             //此情况亦可认为是拆分为 1+(len-1),len-1为偶数,参考哥德巴赫猜想
            }
        }
    }
    
    private boolean isPrime (int n) {
        for(int i=2; i<=Math.sqrt(n); i++) {
            if(n%i==0) {
                return false;
            }
        }
        return true;
    }

编辑于 2020-06-14 02:38:04 回复(0)

问题信息

难度:
30条回答 11302浏览

热门推荐

通过挑战的用户

查看代码