下面是NOIP2015提高组初赛错题整理
具有 n
个节点,e
条边的图采用邻接表存储结构,进行深度优先遍历和广度优先遍历运算的时间复杂度为( O(e+n)
)
解释:因为在遍历时我们有st
数组来防止重复访问,故没每一个节点只访问一次,所以是e+n
双向链表中有两个指针域,llink
和 rlink
,分别指回前驱及后继,设 p
指向链表中的一个结点,q
指向一待插入结点,现要求在 p
前插入 q
,则正确的插入为( )
p->llink->rlink=q;
q->rlink=p;
q->llink=p->llink;
p->llink=q;
解释:
①p
左边元素的右边位置是q
②q
的右边元素是p
③q
左边元素是原来p
的左边元素
④p
的左边元素是q
3.对图 G 中各个结点分别指定一种颜色,使相邻结点颜色不同,则称为图 G 的一个正常着色。正常着色图 G 所必需的最少颜色数,称为 G 的色数。那么下图的色数是
在 1 和 2015 之间(包括 1 和 2015 在内)不能被 4、5、6 三个数任意一个数整除的数有_____个。
解释:
1075个
容斥原理:2015-能被4整除的-能被5整除的-能被6整除的+能被4和5整除的+能被5和6整除的+能被4和6整除的-能被4和5和6整除的
注意几和几表示的是最小公倍数
(双子序列最大和)给定一个长度为n(3≤n≤1000)
的整数序列,要求从中选出两个连续子序列,使得这两个连续子序列的序列和之和最大,最终只需输出这个最大和。一个连续子序列的序列和为该连续子序列中所有数之和。要求:每个连续子序列长度至少为 1,且两个连续子序列之间至少间隔 1 个数。
#include
using namespace std;
const int MAXN = 1000;
int n, i, ans, sum;
int x[MAXN];
int lmax[MAXN];
// lmax[i] 为仅含 x[i] 及 x[i] 左侧整数的连续子序列的序列和中,最大的序列和
int rmax[MAXN];
// rmax[i] 为仅含 x[i] 及 x[i] 右侧整数的连续子序列的序列和中,最大的序列和
int main() {
cin >> n;
for (i = 0; i < n; i++) cin >> x[i];
lmax[0] = x[0] ;
for (i = 1; i < n; i++)
if (lmax[i - 1] <= 0)
lmax[i] = x[i];
else
lmax[i] = lmax[i - 1] + x[i];
for (i = 1; i < n; i++)
if (lmax[i] < lmax[i - 1])
lmax[i] = lmax[i - 1];
①;
for (i = n - 2; i >= 0; i --)
if (rmax[i + 1] <= 0)
②;
else
③;
for (i = n - 2; i >= 0; i --)
if (rmax[i] < rmax[i + 1])
④;
ans = x[ 0] + x [2];
for (i = 1; i < n - 1; i++) {
sum = ⑤;
if (sum > ans)
ans = sum;
}
cout << ans << endl;
return 0;
解释:
①初始化,由于n
为最后一个,所以最大值就是x[n-1]
②同上,如果后面再没有的话最大值就是它本身
③如果不是最后一个,最大值就是后面的最大值再加上它本身
④打擂台求最大长度
⑤最后更新sum
,等于左边的最大加上右边的最大
(最短路径问题)无向连通图 G 有 n 个结点,依次编号为 0,1,2·····,n-2,n-1
。用邻接矩阵的形式给出每条边的边长,要求输出以结点 00为起点出发,到各结点的最短路径长度。
使用 Dijkstra
算法解决该问题:
利用 dist
数组记录当前各结点与起点的已找到的最短路径长度;
每次从未扩展的结点中选取 dist
值最小的结点 v
进行扩展,更新与 v
相邻的结点的 dist
值;
不断进行上述操作直至所有结点均被扩展,此时 dist
数据中记录的值即为各结点与起点的最短路径长度。
#include
using namespace std;
const int MAXV = 100;
int n, i , j, v;
int w[MAXV][MAXV]; // 邻接矩阵,记录边长
// 其中 w[i][j] 为连接结点 i 和结点 j 的无向边长度,若无边则为 -1
int dist[MAXV];
int used[MAXV]; // 记录结点是否已扩展(0:未扩展;1:已扩展)
int main() {
cin >> n;
for (i = 0; i < n; i+ +)
for (j = 0; j < n; j++)
cin >> w[i][j];
dist[0] = 0;
for (i = 1; i < n; i+ +)
dist[i] = -1;
for (i = 0; i < n; i+ +)
used[i] = 0;
while (true) {
① ;
for (i = 0; i < n; i++)
if (used[i] != 1 && dist[i] != -1 && (v == -1 || ② ))
③ ;
if(v == -1)
break;
④ ;
for (i = 0; i < n; i++)
if (w[v][i] != -1 && (dist[i] == -1 || ⑤ ))
dist[i] = dist[v] + w[v][i];
}
for (i = 0; i < n; i++)
cout << dist[i] << endl;
return 0;
}
解释:
①现将v
初始化成-1
表示还没有更新
②打擂台找到与当前点距离最短的点并扩展
③更新,扩展
④记录已经被更新过了
⑤借助该点进行松弛操作