布置宴席最微妙的事情,就是给前来参宴的各位宾客安排座位。无论如何,总不能把两个死对头排到同一张宴会桌旁!这个艰巨任务现在就交给你,对任何一对客人,请编写程序告诉主人他们是否能被安排同席。
输入格式:
输入第一行给出3个正整数:N
(≤100),即前来参宴的宾客总人数,则这些人从1到N
编号;M
为已知两两宾客之间的关系数;K
为查询的条数。随后M
行,每行给出一对宾客之间的关系,格式为:宾客1 宾客2 关系
,其中关系
为1表示是朋友,-1表示是死对头。注意两个人不可能既是朋友又是敌人。最后K
行,每行给出一对需要查询的宾客编号。
这里假设朋友的朋友也是朋友。但敌人的敌人并不一定就是朋友,朋友的敌人也不一定是敌人。只有单纯直接的敌对关系才是绝对不能同席的。
输出格式:
对每个查询输出一行结果:如果两位宾客之间是朋友,且没有敌对关系,则输出No problem
;如果他们之间并不是朋友,但也不敌对,则输出OK
;如果他们之间有敌对,然而也有共同的朋友,则输出OK but...
;如果他们之间只有敌对关系,则输出No way
。
输入样例:
7 8 4
5 6 1
2 7 -1
1 3 1
3 4 1
6 7 -1
1 2 1
1 4 1
2 3 -1
3 4
5 7
2 3
7 2
输出样例:
No problem OK OK but... No way
很迷的题面,令人头秃。训练的时候有一个点没过(因为当时开始写了-1的最短路,最外层循环只for到2……我也不知道当时怎么想的)
#include "bits/stdc++.h"
using namespace std;
const int maxn = 200;
int mp[maxn][maxn], fri[maxn][maxn], ene[maxn][maxn];
int main() {
int n, m, k;
cin >> n >> m >> k;
int a, b, c;
for (int i = 1; i <= m; i++) {
cin >> a >> b >> c;
mp[a][b] = c;
mp[b][a] = c;
if (c == 1) {
fri[a][b] = c;
fri[b][a] = c;
} else {
ene[a][b] = c;
ene[b][a] = b;
}
}
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (fri[i][k] == 1 && fri[k][j] == 1) {
fri[i][j] = 1;
}
}
}
}
while (k--) {
cin >> a >> b;
if (mp[a][b] == -1 && fri[a][b] == 0) {
cout << "No way" << endl;
} else if (mp[a][b] == -1 && fri[a][b] == 1) {
cout << "OK but..." << endl;
} else if (mp[a][b] == 0) {
cout << "OK" << endl;
} else cout << "No problem" << endl;
}
return 0;
}
给定一棵二叉树的中序遍历和前序遍历,请你先将树做个镜面反转,再输出反转后的层序遍历的序列。所谓镜面反转,是指将所有非叶结点的左右孩子对换。这里假设键值都是互不相等的正整数。
输入格式:
输入第一行给出一个正整数N
(≤30),是二叉树中结点的个数。第二行给出其中序遍历序列。第三行给出其前序遍历序列。数字间以空格分隔。
输出格式:
在一行中输出该树反转后的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。
输入样例:
7
1 2 3 4 5 6 7
4 1 3 2 6 5 7
输出样例:
4 6 1 7 5 3 2
用递归可以从一个树得到其遍历序列,那么从遍历序列得到树将其递归反过来就行。反转操作可以忽略,在bfs的时候先插入右儿子就可以了
#include "bits/stdc++.h"
using namespace std;
const int maxn = 100;
int dlr[maxn], ldr[maxn];
int n;
typedef struct node {
int val;
node *l, *r;
} *tree;
tree root = NULL;
void build(tree &t, int start, int lasttime, int len) {
if (len <= 0) {
t = NULL;
return;
}
int now;
t = (tree) malloc(sizeof(node));
t->val = dlr[start];
for (int i = 0; i < n; i++) {
if (ldr[i] == dlr[start]) {
now = i;
break;
}
}
int lenl = now - lasttime;
build(t->l, start + 1, lasttime, lenl);
int lenr = len - 1 - lenl;
build(t->r, start + lenl + 1, now + 1, lenr);
}
void bfs() {
queue<tree> q;
q.push(root);
int flag = 0;
tree temp;
while (!q.empty()) {
if (flag) printf(" ");
flag = 1;
temp = q.front();
q.pop();
cout << temp->val;
if (temp->r != NULL) q.push(temp->r);
if (temp->l != NULL) q.push(temp->l);
}
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
cin >> ldr[i];
}
for (int i = 0; i < n; i++) {
cin >> dlr[i];
}
build(root, 0, 0, n);
bfs();
return 0;
}
将一系列给定数字顺序插入一个初始为空的小顶堆H[]
。随后判断一系列相关命题是否为真。命题分下列几种:
x is the root
:x
是根结点;x and y are siblings
:x
和y
是兄弟结点;x is the parent of y
:x
是y
的父结点;x is a child of y
:x
是y
的一个子结点。
输入格式:
每组测试第1行包含2个正整数N
(≤ 1000)和M
(≤ 20),分别是插入元素的个数、以及需要判断的命题数。下一行给出区间[−10000,10000]内的N
个要被插入一个初始为空的小顶堆的整数。之后M
行,每行给出一个命题。题目保证命题中的结点键值都是存在的。
输出格式:
对输入的每个命题,如果其为真,则在一行中输出T
,否则输出F
。
输入样例:
5 4
46 23 26 24 10
24 is the root
26 and 23 are siblings
46 is the parent of 23
23 is a child of 10
输出样例:
F
T
F
T
判断两个节点是兄弟只要判断他们的父亲是同一个节点就可以了,比赛的时候写了判断他们相邻且一个在奇数节点一个在偶数节点。。。。
// make_heap(heap + 1, heap + 1 + i, greater<int>());
//c++自带的建树函数,默认建大根堆
#include "bits/stdc++.h"
using namespace std;
const int maxn = 1e5;
const int base = 11000;
int heap[maxn];
int ver[maxn];
int n, m;
void up(int p) {
while (p > 1) {
if (heap[p] < heap[p / 2]) {
swap(heap[p], heap[p / 2]);
p /= 2;
} else break;
}
}
int main() {
cin >> n >> m;
int x;
for (int i = 1; i <= n; i++) {
cin >> x;
heap[i] = x;
up(i);
// make_heap(heap + 1, heap + 1 + i, greater<int>());
//c++自带的建树函数,默认建大根堆
}
for (int i = 1; i <= n; i++) {
ver[heap[i] + base] = i;//去掉负数
}
char str[10000];
int a, b;
while (m--) {
scanf("%d", &a);
scanf("%s", str);
if (str[0] == 'a') {
scanf("%d", &b);
scanf("%s", str);
scanf("%s", str);
if (ver[a + base] / 2 == ver[b + base] / 2) {//a和b是兄弟
cout << "T" << endl;
} else cout << "F" << endl;
} else {
scanf("%s", str);
if (str[0] == 'a') {
scanf("%s", str);
scanf("%s", str);
scanf("%d", &b);
if (ver[a + base] / 2 == ver[b + base])//a是b的儿子
cout << "T" << endl;
else
cout << "F" << endl;
} else {
scanf("%s", str);
if (str[0] == 'r') {//a是树根
if (heap[1] == a)
cout << "T" << endl;
else cout << "F" << endl;
} else {
scanf("%s", str);
scanf("%d", &b);
if (ver[a + base] == ver[b + base] / 2)//a是b的父亲
cout << "T" << endl;
else cout << "F" << endl;
}
}
}
}
return 0;
}
本题要求你实现一个天梯赛专属在线地图,队员输入自己学校所在地和赛场地点后,该地图应该推荐两条路线:一条是最快到达路线;一条是最短距离的路线。题目保证对任意的查询请求,地图上都至少存在一条可达路线。
输入格式:
输入在第一行给出两个正整数N
(2 ≤ N
≤ 500)和M
,分别为地图中所有标记地点的个数和连接地点的道路条数。随后M
行,每行按如下格式给出一条道路的信息:
V1 V2 one-way length time
其中V1
和V2
是道路的两个端点的编号(从0到N
-1);如果该道路是从V1
到V2
的单行线,则one-way
为1,否则为0;length
是道路的长度;time
是通过该路所需要的时间。最后给出一对起点和终点的编号。
输出格式:
首先按下列格式输出最快到达的时间T
和用节点编号表示的路线:
Time = T: 起点 => 节点1 => ... => 终点
然后在下一行按下列格式输出最短距离D
和用节点编号表示的路线:
Distance = D: 起点 => 节点1 => ... => 终点
如果最快到达路线不唯一,则输出几条最快路线中最短的那条,题目保证这条路线是唯一的。而如果最短距离的路线不唯一,则输出途径节点数最少的那条,题目保证这条路线是唯一的。
如果这两条路线是完全一样的,则按下列格式输出:
Time = T; Distance = D: 起点 => 节点1 => ... => 终点
输入样例1:
10 15
0 1 0 1 1
8 0 0 1 1
4 8 1 1 1
5 4 0 2 3
5 9 1 1 4
0 6 0 1 1
7 3 1 1 2
8 3 1 1 2
2 5 0 2 2
2 1 1 1 1
1 5 0 1 3
1 4 0 1 1
9 7 1 1 3
3 1 0 2 5
6 3 1 2 1
5 3
输出样例1:
Time = 6: 5 => 4 => 8 => 3
Distance = 3: 5 => 1 => 3
输入样例2:
7 9
0 4 1 1 1
1 6 1 3 1
2 6 1 1 1
2 5 1 2 2
3 0 0 1 1
3 1 1 3 1
3 2 1 2 1
4 5 0 2 2
6 5 1 2 1
3 5
输出样例2:
Time = 3; Distance = 4: 3 => 2 => 5
读题读题读题,比赛时读题要尽量的慢,准,稳。
#include "bits/stdc++.h"
using namespace std;
const int maxn = 600;
int timemap[maxn][maxn], lenmap[maxn][maxn];
int lendist[maxn], lt[maxn], tl[maxn], timedist[maxn], timepre[maxn], timevis[maxn];
int lenpre[maxn], lenvis[maxn];
int n, m, s, d;
vector<int> ans1, ans2;
bool check() {
if (ans1.size() != ans2.size()) return false;
for (int i = 0; i < ans1.size(); i++) {
if (ans1[i] != ans2[i]) return false;
}
return true;
}
void dij1() {
memset(timedist, 0x3f, sizeof(timedist));
memset(timevis, 0, sizeof(timevis));
memset(timepre, -1, sizeof(timepre));
memset(lendist, 0x3f, sizeof(lendist));
memset(lenvis, 0, sizeof(lenvis));
memset(lenpre, -1, sizeof(lenpre));
memset(lt, 0x3f, sizeof(lt));
memset(tl, 0x3f, sizeof(lt));
timedist[s] = 0;
lendist[s] = 0;
lt[s] = 1;
tl[s] = 0;
for (int i = 1; i < n; i++) {
int x = -1;
for (int j = 0; j < n; j++) {
if (!timevis[j] && (x == -1 || timedist[j] < timedist[x])) x = j;
}
timevis[x] = 1;
for (int j = 0; j < n; j++) {
if (timedist[x] + timemap[x][j] < timedist[j]) {
timedist[j] = timedist[x] + timemap[x][j];
tl[j] = tl[x] + lenmap[x][j];
timepre[j] = x;
} else if (timedist[x] + timemap[x][j] == timedist[j] &&
tl[x] + lenmap[x][j] < tl[j]) {
tl[j] = tl[x] + lenmap[x][j];
timepre[j] = x;
}
}
x = -1;
for (int j = 0; j < n; j++) {
if (!lenvis[j] && (x == -1 || lendist[j] < lendist[x])) x = j;
}
lenvis[x] = 1;
for (int j = 0; j < n; j++) {
if (lendist[x] + lenmap[x][j] < lendist[j]) {
lendist[j] = lendist[x] + lenmap[x][j];
lenpre[j] = x;
lt[j] = lt[x] + 1;
} else if (lendist[x] + lenmap[x][j] == lendist[j]
&& lt[x] + 1 < lt[j]) {
lenpre[j] = x;
lt[j] = lt[x] + 1;
}
}
}
ans1.push_back(d);
int x = timepre[d];
while (x != -1) {
ans1.push_back(x);
x = timepre[x];
}
ans2.push_back(d);
x = lenpre[d];
while (x != -1) {
ans2.push_back(x);
x = lenpre[x];
}
if (check()) {
printf("Time = %d; Distance = %d: ", timedist[d], lendist[d]);
int flag = 0;
for (int i = ans1.size() - 1; i >= 0; i--) {
if (flag) printf(" => ");
flag = 1;
printf("%d", ans1[i]);
}
printf("\n");
return;
}
printf("Time = %d: ", timedist[d]);
int flag = 0;
for (int i = ans1.size() - 1; i >= 0; i--) {
if (flag) printf(" => ");
flag = 1;
printf("%d", ans1[i]);
}
printf("\n");
printf("Distance = %d: ", lendist[d]);
flag = 0;
for (int i = ans2.size() - 1; i >= 0; i--) {
if (flag) printf(" => ");
flag = 1;
printf("%d", ans2[i]);
}
printf("\n");
}
int main() {
//freopen("input.txt", "r", stdin);
memset(lenmap, 0x3f, sizeof(lenmap));
memset(timemap, 0x3f, sizeof(timemap));
cin >> n >> m;
int a, b, c, dd, e;
for (int i = 0; i < m; i++) {
cin >> a >> b >> c >> dd >> e;
if (!c) {
timemap[b][a] = e;
lenmap[b][a] = dd;
}
timemap[a][b] = e;
lenmap[a][b] = dd;
}
cin >> s >> d;
dij1();
return 0;
}
喊山 (30 分)
喊山,是人双手围在嘴边成喇叭状,对着远方高山发出“喂—喂喂—喂喂喂……”的呼唤。呼唤声通过空气的传递,回荡于深谷之间,传送到人们耳中,发出约定俗成的“讯号”,达到声讯传递交流的目的。原来它是彝族先民用来求援呼救的“讯号”,慢慢地人们在生活实践中发现了它的实用价值,便把它作为一种交流工具世代传袭使用。(图文摘自:http://news.xrxxw.com/newsshow-8018.html)
一个山头呼喊的声音可以被临近的山头同时听到。题目假设每个山头最多有两个能听到它的临近山头。给定任意一个发出原始信号的山头,本题请你找出这个信号最远能传达到的地方。
输入格式:
输入第一行给出3个正整数n
、m
和k
,其中n
(≤10000)是总的山头数(于是假设每个山头从1到n
编号)。接下来的m
行,每行给出2个不超过n
的正整数,数字间用空格分开,分别代表可以听到彼此的两个山头的编号。这里保证每一对山头只被输入一次,不会有重复的关系输入。最后一行给出k
(≤10)个不超过n
的正整数,数字间用空格分开,代表需要查询的山头的编号。
输出格式:
依次对于输入中的每个被查询的山头,在一行中输出其发出的呼喊能够连锁传达到的最远的那个山头。注意:被输出的首先必须是被查询的个山头能连锁传到的。若这样的山头不只一个,则输出编号最小的那个。若此山头的呼喊无法传到任何其他山头,则输出0。
输入样例:
7 5 4
1 2
2 3
3 1
4 5
5 6
1 4 5 7
输出样例:
2
6
4
0
简单bfs
#include "bits/stdc++.h"
using namespace std;
const int maxn = 10010;
vector<int> e[maxn];
struct node {
int pos, dis;
};
int n, m, k;
int vis[maxn];
int ans, dis;
void bfs(int x) {
queue<node> q;
node temp, tt;
temp.dis = 0;
temp.pos = x;
vis[x] = 1;
q.push(temp);
while (!q.empty()) {
temp = q.front();
q.pop();
if (temp.dis > dis) {
dis = temp.dis;
ans = temp.pos;
} else if (temp.dis == dis && temp.pos < ans) {
ans = temp.pos;
}
for (auto p:e[temp.pos]) {
if (!vis[p]) {
vis[p] = 1;
tt.pos = p;
tt.dis = temp.dis + 1;
q.push(tt);
}
}
}
}
int main() {
cin >> n >> m >> k;
int a, b;
for (int i = 0; i < m; i++) {
cin >> a >> b;
e[a].push_back(b);
e[b].push_back(a);
}
while (k--) {
cin >> a;
ans = 0x3f3f3f3f;
dis = -0x3f3f3f3f;
bfs(a);
cout << (ans == a ? 0 : ans) << endl;
memset(vis, 0, sizeof(vis));
}
return 0;
}
正如我们所知,中国古代长城的建造是为了抵御外敌入侵。在长城上,建造了许多烽火台。每个烽火台都监视着一个特定的地区范围。一旦某个地区有外敌入侵,值守在对应烽火台上的士兵就会将敌情通报给周围的烽火台,并迅速接力地传递到总部。
现在如图1所示,若水平为南北方向、垂直为海拔高度方向,假设长城就是依次相联的一系列线段,而且在此范围内的任一垂直线与这些线段有且仅有唯一的交点。
图 1
进一步地,假设烽火台只能建造在线段的端点处。我们认为烽火台本身是没有高度的,每个烽火台只负责向北方(图1中向左)瞭望,而且一旦有外敌入侵,只要敌人与烽火台之间未被山体遮挡,哨兵就会立即察觉。当然,按照这一军规,对于南侧的敌情各烽火台并不负责任。一旦哨兵发现敌情,他就会立即以狼烟或烽火的形式,向其南方的烽火台传递警报,直到位于最南侧的总部。
以图2中的长城为例,负责守卫的四个烽火台用蓝白圆点示意,最南侧的总部用红色圆点示意。如果红色星形标示的地方出现敌情,将被哨兵们发现并沿红色折线将警报传递到总部。当然,就这个例子而言只需两个烽火台的协作,但其他位置的敌情可能需要更多。
然而反过来,即便这里的4个烽火台全部参与,依然有不能覆盖的(黄色)区域。
图 2
另外,为避免歧义,我们在这里约定,与某个烽火台的视线刚好相切的区域都认为可以被该烽火台所监视。以图3中的长城为例,若A、B、C、D点均共线,且在D点设置一处烽火台,则A、B、C以及线段BC上的任何一点都在该烽火台的监视范围之内。
图 3
好了,倘若你是秦始皇的太尉,为不致出现更多孟姜女式的悲剧,如何在保证长城安全的前提下,使消耗的民力(建造的烽火台)最少呢?
输入格式:
输入在第一行给出一个正整数N
(3 ≤ N
≤105),即刻画长城边缘的折线顶点(含起点和终点)数。随后N
行,每行给出一个顶点的x
和y
坐标,其间以空格分隔。注意顶点从南到北依次给出,第一个顶点为总部所在位置。坐标为区间[−109,109)内的整数,且没有重合点。
输出格式:
在一行中输出所需建造烽火台(不含总部)的最少数目。
输入样例:
10
67 32
48 -49
32 53
22 -44
19 22
11 40
10 -65
-1 -23
-3 31
-7 59
输出样例:
2
求凸包的思想,利用向量叉积判断,如果两个点之间隔着一个上凸(角abc),则从a观测不到c,需在b建一个瞭望台
#include "bits/stdc++.h"
using namespace std;
const int maxn = 1e5+100;
struct point {
int x, y;
int pos;
} st[maxn];
int vis[maxn];
bool check(point a, point b, point c) {
return 1ll * (b.x - a.x) * (c.y - b.y) - (c.x - b.x) * (b.y - a.y) <= 0;
}
int main() {
int n;
cin >> n;
point pos;
int s = 0;
for (int i = 0; i < n; i++) {
cin >> pos.x >> pos.y;
pos.pos = i;
if (s >= 1) {
while (s >= 2 && check(st[s - 2], st[s - 1], pos))
s--;
vis[st[s - 1].pos] = 1;
}
st[s++] = pos;
}
int ans = 0;
for (int i = 1; i <= n; i++) {
if (vis[i])ans++;
}
cout << ans << endl;
return 0;
}
来源:oschina
链接:https://my.oschina.net/u/4366606/blog/3612927