SMU Summer 2024 第一周周报

总结:

学习使用了 以二分查找为底层的 lower_bound 和 upper_bound 函数

强化了Dijkstra算法在题目中的实际应用

学会了while(scanf("%d",&N)!=EOF)这一写法,用于无输入结束限制的题目中

学会了素数表的生成,可以在一些题目中拿来代替bool isPrime()函数,以优化时间复杂度

二分查找与升/降序子数列:

以lower_bound 和 upper_bound 函数不断寻找比当前数大的/小的数的位置,可便利的得出升/降序子数列的结尾/数目

例题1:

登录—专业IT笔试面试备考平台_牛客网

AC代码:

#include<bits/stdc++.h>
using namespace std;

#define int long long

int song[500005],sum[500005];

signed main(){
    int n,q;
    cin>>n>>q;
    cin>>song[1];
    sum[1]=song[1];
    for(int i=2;i<=n;i++){
        cin>>song[i];
        sum[i] = song[i]+sum[i-1];
    }
    while(q--){
        int x;
        cin>>x;
        int ans = upper_bound(sum+1,sum+1+n,x)-sum;
        cout<<ans<<endl;
    }
    return 0;
}

例题2:

Sequence Decomposing


此题的本质就是找输入数列的升序子列的最小数目,但是暴力会超时,使用upper_bound(begin , end , val , less<type>() );函数来进行二分查找即可顺利AC

AC代码:

#include<bits/stdc++.h>
using namespace std;
int arr[100005];
int main(){
    int n,x,k,ans=0;
    cin>>n;
    while(n--){
        cin>>x;
        k=upper_bound(arr+1,arr+ans+1,x,greater<int>())-arr; 
            //cout<<"k= "<<k<<" ans= "<<ans<<endl;
        if(k>ans){
            arr[++ans]=x;
        }
        else{
            arr[k]=x;
        }
    }
    cout<<ans<<endl;
    return 0;
}

Dijkstra:

在学习离散数学之后对此算法的运作原理理解更加透彻,对邻接矩阵的运用也更加了解了

例题:

AC代码:

#include<bits/stdc++.h>
using namespace std;
 
const int INF = 1e9; 
 
int G[10][10];
 
void Dijkstra(int n, int s,int G[][10], vector<bool> &vis, vector<int> &d, vector<int> &pre)
{
    fill(vis.begin(), vis.end(), false);
    fill(d.begin(), d.end(), INF);
    d[s] = 0;
    for (int i = 0; i < n; ++i)
    {
        pre[i] = i;
    }
 
    for (int i = 0; i < n; ++i)
    {
        int u = -1;
        int MIN = INF;
        for (int j = 0; j < n; ++j)
        {
            if (!vis[j] && d[j] < MIN)
            {
                u = j;
                MIN = d[j];
            }
        }
 
        if (u == -1)
        {
            return;
        }
 
        vis[u] = true;
        for (int v = 0; v < n; ++v)
        {
            if (!vis[v] && G[u][v] != INF && d[u] + G[u][v] < d[v])
            {
                d[v] = d[u] + G[u][v];  
                pre[v] = u;              
            }
        }
    }
}
 
int main()
{
    int chang,kuan;
    cin>>chang>>kuan;
    int n = 10;
    
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            cin>>G[i][j];
        }
    }
    
    vector<bool> vis(n);
    vector<int> d(n);
    vector<int> pre(n);
 
    int x=0,wall[10]={0};
 
    for(int i=0;i<chang;i++){
        for(int j=0;j<kuan;j++){
            cin>>x;
            if(x == -1) ;
            else{
                wall[x]++;
            }
        }
    }
 
    int ans = 0;
    Dijkstra(n, 0, G, vis, d, pre);
    ans += wall[0] * d[1];
 
    for(int i=2;i<10;i++){
        Dijkstra(n, i, G, vis, d, pre);
        ans += wall[i] * d[1];
    }
 
    cout<<ans<<endl;
 
    return 0;
}

无明确结束输入与素数表:

直接上题:

寻找素数对
哥德巴赫猜想大家都知道一点吧.我们现在不是想证明这个结论,而是想在程序语言内部能够表示的数集中,任意取出一个偶数,来寻找两个素数,使得其和等于该偶数.
做好了这件实事,就能说明这个猜想是成立的.
由于可以有不同的素数对来表示同一个偶数,所以专门要求所寻找的素数对是两个值最相近的.

输入描述

输入中是一些偶整数M(5<M<=10000).

输出描述

对于每个偶数,输出两个彼此最接近的素数,其和等于该偶数.

用例输入 1 

20 30 40
用例输出 1 

7 13
13 17
17 23
据题知,从输入数的二分之一处开始向左向右寻找可以得到所需答案,由于题目中给出了数据范围,通过打素数表的方式可以很便利的解决问题

AC代码:

#include<bits/stdc++.h>
using namespace std; 
int Pr[10010]; // 定义一个整型数组,用于存储素数信息
void Cr() // 定义一个函数,用于生成素数表
{
    int i,j; // 定义两个整型变量,用于循环计数
    for(i=1;i<=10000;i++)Pr[i]=1; // 初始化素数表,将所有元素设为1(假设所有数都是素数)
    for(i=2;i<=10000;i++) // 从2开始遍历到10000
    {
        if(Pr[i]) // 如果当前数是素数
            for(j=2;i*j<=10000;j++)Pr[i*j]=0; // 将该数的倍数标记为非素数
    }
    return ; // 函数结束,返回空
}
int main() // 主函数
{
    int N,C,X,i; // 定义四个整型变量
    Cr(); // 调用Cr函数,生成素数表
    while(scanf("%d",&N)!=EOF) // 当输入不为EOF时,继续循环
    {
           X=N/2; // 计算N的一半
           for(i=0;X-i>=1;i++) // 从0开始遍历到X的一半
           {
               if(Pr[X-i]&&Pr[X+i]) // 如果X-i和X+i都是素数
                {
                    printf("%d %d",X-i,X+i); // 输出这两个素数
                    break; // 跳出循环
                }
           }
    }
    return 0; // 程序正常结束,返回0
}

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值