题意概述

  • 对数轴上的n个点,必须建立收集站
  • 相邻两收集站的距离若不为素数或1,则在其中间尽量少的建立若干收集站使其满足条件
  • 欲求解最少建立收集站的个数

方法一:哥德巴赫猜想

思路与具体做法

哥德巴赫猜想——引自百度百科
“强哥德巴赫猜想”或“关于偶数的哥德巴赫猜想”:任一大于2的偶数都可写成两个素数之和
“弱哥德巴赫猜想”或“关于奇数的哥德巴赫猜想”:任一个大于7的奇数都能被表示成三个奇质数的和

  • 若两站之间距离为素数或1:
    • 则两站间不需修站
  • 若两站之间距离为偶合数:
    • 根据强哥德巴赫猜想,大于2的偶数距离间都不需要修建(小于等于2的偶数只有2,为素数)
  • 若两站之间距离为奇合数:
    • 因为奇数只可以拆分成奇数+偶数,现在要求拆分出的这两段子距离也都是素数,而2是唯一的偶数的素数,所以此时若拆分出来的奇数也是素数,则两站间最少修建一个站台
    • 若不满足上述情况,根据弱哥德巴赫猜想,大于7的奇数距离都至少能被拆分成3个奇质数,(小于等于7的奇数满足素数或1的情况)

图片说明

class Solution {
public:
    bool isprime(int n){
        if(n==1)return true;//判断1 
        for(int i=2;i*i<=n;i++){//判断素数 
            if(n%i==0)return false;
        }
        return true;
    }
    int work(int n, int* a, int aLen){
        int ans=1;//第一个站一定要建 
        for(int i=1;i<n;i++){//从第二个站开始遍历 
            int distance=a[i]-a[i-1];
            if(isprime(distance))ans++;//两站距离为素数,则直接建立该站,两站间不需再建站 
            else{//两站距离为合数
                if(distance%2==0)ans+=2;//偶合数,强哥德巴赫猜想 
                else{//奇合数 
                    if(isprime(distance-2))ans+=2;//奇数=奇数+偶数,拆分 
                    else  ans+=3;//弱哥德巴赫猜想            
                }
            }
        } 
        return ans;
    }
};

时间复杂度和空间复杂度分析

时间复杂度: , n为点数,为一次判断素数的最大时间复杂度
空间复杂度: ,仅用到了一个整形变量ans用于记录车站数量

方法二:动态规划(超时)

思路与具体做法

  • dp[i]:长度为i的距离内可新建的站数目
  • 首先计算题目中已给的两站间最大距离
  • 接着枚举所有站间距离,直到站间最大距离
  • 对每一个站间距离
    • 为素数,说明这段站间距离i不需要新建站
    • 为合数,则对这段站间距离i进行转态转移
  • 转态转移:
    • 从距离1开始枚举站间距离的所有素数j,对站间距i,
      • 若它不进行分割,站间距离i不变,可新建的站数目不变,
      • 若它可进行分割,站间距离i减少j,可新建的站数目加1,
  • 注意:
    • 因为需要枚举一段距离内的所有素数,所以这里会超时,即使用欧拉筛法进行打表,得到一个素数表,也会出现运行超时的情况
class Solution {
public:
    int pNum=0;//素数个数
    void Find_Prime2(int maxn,int p[],int prime[]){
        for(int i=2;i<maxn;i++){    
            if(p[i]==false){ 
                prime[pNum++]=i;
            } 
            for(int j=0;j<pNum&&i*prime[j]<maxn;j++){//遍历每一个已找到的素数
                p[i*prime[j]]=true;//这个素数的倍数是合数
                if(i%prime[j]==0)break;//因为每个数只被它的最小质因子筛一次,在此之后的质数不用筛
            } 
        } 
    }
    int work(int n, int* a, int aLen) {
        int maxx=1;//两站间的最大距离 
        for(int i=1;i<n;i++){
            maxx=max(maxx,a[i]-a[i-1]);
        } 
        int p[maxx+1];//初始都是素数
        memset(p,0,sizeof(p));
        int prime[maxx+1];//素数表        
        Find_Prime2(maxx+1,p,prime);//打表,表长为两点之间最长距离 
        int dp[maxx+1];//两站需建多少站点 
        for(int i=1;i<=maxx;i++){
            if(!p[i]||i==1){//距离为素数,中间不用建站 
                dp[i]=0;
            }else{//距离不为素数 
                dp[i]=0x3fffffff;
                for(int j=1;j<=i;j++){
                    if(!p[j]){
                        dp[i]=min(dp[i],dp[i-j]+1);
                    }
                }
            }
        }
        int ans=n;
        for(int i=1;i<n;i++){
            ans+=dp[a[i]-a[i-1]];
        }
        return ans;
    }
};

时间复杂度和空间复杂度分析

时间复杂度:,d为站间最大距离,dp数组求解两层循环
空间复杂度:,d为站间最大距离,这里仅用到了一个长度为d+1的dp数组