8.25 2016NOIP提高组初赛错题整理
单项选择题
第 8 题 (1.5 分) G 是一个非连通简单无向图,共有 28 条边,则该图至少有( )个顶点。
非连通代表图至少由两部分组成,简单说明图没有重边和自环
为了使点数尽可能少
需要使边尽可能密集
把一个点孤立出来
剩下的连成完全图
点数为
n
n
n的完全图边数为
n
(
n
−
1
)
2
\frac{n(n-1)}{2}
2n(n−1)
n
(
n
−
1
)
2
=
28
\frac{n(n-1)}{2}=28
2n(n−1)=28
n
1
=
8
,
n
2
=
−
7
<
0
舍
去
n1=8,n2=-7<0舍去
n1=8,n2=−7<0舍去
加上孤立的那个点
共计9个
不定项选择题
略
问题求解
略
阅读程序写结果
略
补全代码
第 27 题 (交朋友)根据社会学研究表明,人们都喜欢找和自己身高相近的人做朋友。 现在有 nn
名身高两两不相同的同学依次走入教室,调查人员想预测每个人在走入教室的瞬间最想和已经进入教室的哪个人做朋友。当有两名同学和这名同学的身高差一样时,这名同学会更想和高的那个人做朋友。比如一名身高为
1.801.80 米的同学进入教室时,有一名身高为 1.79 米的同学和一名身高为 1.81米的同学在教室里,那么这名身高为 1.80 米的同学会更想和身高为 1.81
米的同学做朋友。对于第一个走入教室的同学我们不做预测。由于我们知道所有人的身高和走进教室的次序,所以我们可以采用离线的做法来解决这样的问题,我们用排序加链表的方式帮助每一个人找到在他之前进入教室的并且和他身高最相近的人。
#include <iostream>
using namespace std;
#define MAXN 200000
#define infinity 2147483647
int answer[MAXN], height[MAXN], previous[MAXN], next[MAXN]; int rank[MAXN];
int n;
void sort(int l, int r) {//排序
int x = height[rank[(l + r) / 2]], i = l, j = r, temp;
while (i <= j)//注意这里有等于号
{
while (height[rank[i]] < x) i++;
while (height[rank[j]] > x) j--;
if ( ___(1)___ ) {
temp = rank[i]; rank[i] = rank[j]; rank[j] = temp;
i++; j--;
}
}
if (i < r) sort(i, r);
if (l < j) sort(l, j);
}
int main()
{
cin >> n;
int i, higher, shorter;
for (i = 1; i <= n; i++) {
cin >> height[i];
rank[i] = i;
}
sort(1, n);
for (i = 1; i <= n; i++) {
previous[rank[i]] = rank[i - 1];
___(2)___ ;
}
for (i = n; i >= 2; i--){//注意这里的从后往前
higher = shorter = infinity;
if (previous[i] !=0)
shorter = height[i] - height[previous[i]];
if (next[i] != 0)
___(3)___ ;
if ( ___(4)___ )
answer[i] = previous[i];
else
answer[i] = next[i];
next[previous[i]] = next[i];
___(5)___ ;
}
for (i = 2; i <= n; i++)
cout << i << ":" << answer[i];
return 0;
}
分析详见注释
题目答案
填空位置 ①:
i <= j//与此代码前标记的i<=j保持一致
填空位置 ②:
next[rank[i]] = rank[i+1]//搭建链表
填空位置 ③:
higher = height[next[i]] - height[i]//仿写即可
填空位置 ④:
shorter < higher//优先选择身高差小的
填空位置 ⑤:
previous[next[i]] = previous[i]//删除最后一个人,因为先进入的人无法选择后进入的人为朋友
第 27 题 (交通中断)有一个小国家,国家内有 n座城市和 m 条双向的道路,每条道路连接着两座不同的城市。其中 11
号城市为国家的首都。由于地震频繁可能导致某一个城市与外界交通全部中断。这个国家的首脑想知道,如果只有第 i(i>1)
个城市因地震而导致交通中断时,首都到多少个城市的最短路径长度会发生改变。如果因为无法通过第
i个城市而导致从首都出发无法到达某个城市,也认为到达该城市的最短路径长度改变。对于每一个城市 i,假定只有第 i 个城市与外界交通中断,输出有多少个城市会因此导致到首都的最短路径长度改变。
我们采用邻接表的方式存储图的信息,其中 head[x] 表示顶点 x 的第一条 边的编号,next[i] 表示第 i 条边的下一条边的编号,
point[i] 表示第 i 条边的终点,weight[i] 表示第 i 条边的长度。
#include <iostream>
#include <cstring>
using namespace std;
#define MAXN 6000
#define MAXM 100000
#define infinity 2147483647
int head[MAXN], next[MAXM], point[MAXM], weight[MAXM];
int queue[MAXN], dist[MAXN], visit[MAXN];
int n, m, x, y, z, total = 0, answer;
void link(int x,int y,int z) {
total++;
next[total] = head[x]; head[x] = total; point[total] = y; weight[total] = z; total++;
next[total] = head[y]; head[y] = total; point[total] = x; weight[total] = z;
}
//相当于模板中的add函数*2
//用于建立无向边
int main() {
int i, j, s, t; cin >> n >> m;
for (i = 1; i <= m; i++) {
cin >> x >> y >> z;
link(x, y, z);
}
for (i = 1; i <= n; i++) dist[i] = infinity;
___(1)___ ;
queue[1] = 1;
visit[1] = 1;
s = 1;
t = 1;
// 使用 SPFA 求出第一个点到其余各点的最短路长度
while (s <= t) {
x = queue[s % MAXN];
j = head[x];
while (j != 0) {
if ( ___(2)___ ) {
dist[point[j]] = dist[x] + weight[j];
if (visit[point[j]] == 0) {
t++;
queue[t % MAXN] = point[j];
visit[point[j]] = 1;
}
}
j = next[j];
}
___(3)___ ;
s++;
}
for (i = 2; i <= n; i++) {
queue[1] = 1;
memset(visit, 0, sizeof(visit));
visit[1] = 1;
s = 1;
t = 1;
while (s <= t) { // 判断最短路长度是否不变
x = queue[s];
j = head[x];
while (j != 0) {
if (point[j] != i && ___(4)___ &&visit[point[j]] == 0) {
___(5)___ ;
t++;
queue[t] = point[j];
}
j = next[j];
}
s++;
}
answer = 0;
for (j = 1; j <= n; j++)
answer += 1 - visit[j];
cout << i << ":" << answer - 1 << endl;
}
return 0;
}
模板题背熟就完事了
题目答案
填空位置 ①:
dist[1] = 0
填空位置 ②:
dist[x] + weight[j] < dist[point[j]]
填空位置 ③:
visit[x] = 0
填空位置 ④:
dist[x] + weight[j] == dist[point[j]]
填空位置 ⑤:
visit[point[j]] = 1