总结:
学习使用了 以二分查找为底层的 lower_bound 和 upper_bound 函数
强化了Dijkstra算法在题目中的实际应用
学会了while(scanf("%d",&N)!=EOF)这一写法,用于无输入结束限制的题目中
学会了素数表的生成,可以在一些题目中拿来代替bool isPrime()函数,以优化时间复杂度
二分查找与升/降序子数列:
以lower_bound 和 upper_bound 函数不断寻找比当前数大的/小的数的位置,可便利的得出升/降序子数列的结尾/数目
例题1:
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
}