7-3 冰岛人
分数 25 提交通过率 0/166(0.00%)
2018年世界杯,冰岛队因1:1平了强大的阿根廷队而一战成名。好事者发现冰岛人的名字后面似乎都有个“松”(son),于是有网友科普如下:
冰岛人沿用的是维京人古老的父系姓制,孩子的姓等于父亲的名加后缀,如果是儿子就加 sson,女儿则加 sdottir。因为冰岛人口较少,为避免近亲繁衍,本地人交往前先用个 App 查一下两人祖宗若干代有无联系。本题就请你实现这个 App 的功能。
输入格式:
输入首先在第一行给出一个正整数 N(1<N≤105),为当地人口数。随后 N 行,每行给出一个人名,格式为:名 姓(带性别后缀)
,两个字符串均由不超过 20 个小写的英文字母组成。维京人后裔是可以通过姓的后缀判断其性别的,其他人则是在姓的后面加 m
表示男性、f
表示女性。题目保证给出的每个维京家族的起源人都是男性。
随后一行给出正整数 M,为查询数量。随后 M 行,每行给出一对人名,格式为:名1 姓1 名2 姓2
。注意:这里的姓
是不带后缀的。四个字符串均由不超过 20 个小写的英文字母组成。
题目保证不存在两个人是同名的。
输出格式:
对每一个查询,根据结果在一行内显示以下信息:
- 若两人为异性,且五代以内无公共祖先,则输出
Yes
; - 若两人为异性,但五代以内(不包括第五代)有公共祖先,则输出
No
; - 若两人为同性,则输出
Whatever
; - 若有一人不在名单内,则输出
NA
。
所谓“五代以内无公共祖先”是指两人的公共祖先(如果存在的话)必须比任何一方的曾祖父辈分高。
输入样例:
15
chris smithm
adam smithm
bob adamsson
jack chrissson
bill chrissson
mike jacksson
steve billsson
tim mikesson
april mikesdottir
eric stevesson
tracy timsdottir
james ericsson
patrick jacksson
robin patricksson
will robinsson
6
tracy tim james eric
will robin tracy tim
april mike steve bill
bob adam eric steve
tracy tim tracy tim
x man april mikes
输出样例:
Yes
No
No
Whatever
Whatever
NA
一些知识:
一、map.count()
map.count()返回的是0或1
0表示查找失败
1表示map中存在该键二、map.find()
map.find()返回的是迭代器
如果查找成功,则返回该键所在位置的迭代器
失败则返回map.end()所在位置的迭代器三、string.back()
返回string的最后一个字符
#include<bits/stdc++.h>
using namespace std;
typedef pair<bool, string> pbs;
int n, m;
map<string, pbs> mp;
string s1, s2, tmp;
void check(string s1, string s2) {
int ct1 = 0, ct2;
while (s1 != "") {
tmp = s2;
ct2 = 0;
while (tmp != "") {
if (s1 == tmp && (ct1 < 4 || ct2 < 4)) {
puts("No");
return;
}
if (ct1 >= 4 && ct2 >= 4) {
puts("Yes");
return;
}
tmp = mp[tmp].second;
ct2++;
}
s1 = mp[s1].second;
ct1++;
}
puts("Yes");
return;
}
int main() {
cin >> n;
while (n--) {
cin >> s1 >> s2;
if (s2.back() == 'n') mp[s1] = { 1, s2.substr(0, s2.size() - 4) };
else if (s2.back() == 'r') mp[s1] = { 0, s2.substr(0, s2.size() - 7) };
else if (s2.back() == 'm') mp[s1].first = 1;
else mp[s1].first = 0;
}
cin >> m;
while (m--) {
cin >> s1 >> tmp >> s2 >> tmp;
if (!mp.count(s1) || !mp.count(s2)) puts("NA");
else if (mp[s1].first == mp[s2].first) puts("Whatever");
else check(s1, s2);
}
return 0;
}
呼~~~补完啦 小总结:题目刷太少 知识点掌握不全面 考试状态不好。
7-5 玩转二叉树
分数 3 / 25 提交通过率 6/197(3.05%)
给定一棵二叉树的中序遍历和前序遍历,请你先将树做个镜面反转,再输出反转后的层序遍历的序列。所谓镜面反转,是指将所有非叶结点的左右孩子对换。这里假设键值都是互不相等的正整数。
输入格式:
输入第一行给出一个正整数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
妈的这题做过的,考试的时候算下标算死了醉了。
#include<bits/stdc++.h>
using namespace std;
typedef struct TNode* tree;
struct TNode {
int data;
tree l, r;
};
const int N = 100;
int n, in[N], pre[N];
vector<int> v;
tree Create(int inl, int prel, int len) {
if (len == 0) {
return NULL;
}
tree bt = new TNode;
int i, l, r = pre[prel];
bt->data = r;
for (i = inl; i < inl + len; ++i)
if (in[i] == r) break;
l = i - inl;
bt->l = Create(inl, prel + 1, l);
bt->r = Create(inl + l + 1, prel + 1 + l, len-l-1);
return bt;
}
void level(tree t) {
queue<tree> q;
q.emplace(t);
while (q.size()) {
tree tmp = q.front(); q.pop();
if (tmp->r) q.emplace(tmp->r);
if (tmp->l) q.emplace(tmp->l);
v.emplace_back(tmp->data);
}
}
int main() {
cin >> n;
for (int i = 0; i < n; ++i) cin >> in[i];
for (int i = 0; i < n; ++i) cin >> pre[i];
tree t = Create(0, 0, n);
level(t);
for (int i = 0; i < v.size(); ++i) {
if (i) cout << ' ' << v[i];
else cout << v[i];
}
return 0;
}
7-6 完全二叉树的层序遍历
分数 25 3/228(1.32%)
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是完美二叉树。对于深度为 D 的,有 N 个结点的二叉树,若其结点对应于相同深度完美二叉树的层序遍历的前 N 个结点,这样的树就是完全二叉树。
给定一棵完全二叉树的后序遍历,请你给出这棵树的层序遍历结果。
输入格式:
输入在第一行中给出正整数 N(≤30),即树中结点个数。第二行给出后序遍历序列,为 N 个不超过 100 的正整数。同一行中所有数字都以空格分隔。
输出格式:
在一行中输出该树的层序遍历序列。所有数字都以 1 个空格分隔,行首尾不得有多余空格。
输入样例:
8
91 71 2 34 10 15 55 18
输出样例:
18 34 55 71 2 10 15 91
这题纯纯送分,因为他是完全二叉树,所以只要模拟递归一下后序遍历并存入数组,妈的考试没做到傻蛋了。
#include<bits/stdc++.h>
using namespace std;
const int N = 50;
int n, t[N];
void dfs(int i){
if(i*2 <= n) dfs(i*2);
if(i*2+1 <= n) dfs(i*2+1);
cin >> t[i];
}
int main(){
cin >> n;
dfs(1);
for(int i = 1; i <= n; ++i){
cout << t[i];
if(i < n) cout << ' ';
}
return 0;
}
7-7 家庭房产
分数 25 提交通过率 0/67(0.00%)
给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数、人均房产面积及房产套数。
输入格式:
输入第一行给出一个正整数N(≤1000),随后N行,每行按下列格式给出一个人的房产:
编号 父 母 k 孩子1 ... 孩子k 房产套数 总面积
其中编号
是每个人独有的一个4位数的编号;父
和母
分别是该编号对应的这个人的父母的编号(如果已经过世,则显示-1
);k
(0≤k
≤5)是该人的子女的个数;孩子i
是其子女的编号。
输出格式:
首先在第一行输出家庭个数(所有有亲属关系的人都属于同一个家庭)。随后按下列格式输出每个家庭的信息:
家庭成员的最小编号 家庭人口数 人均房产套数 人均房产面积
其中人均值要求保留小数点后3位。家庭信息首先按人均面积降序输出,若有并列,则按成员编号的升序输出。
输入样例:
10
6666 5551 5552 1 7777 1 100
1234 5678 9012 1 0002 2 300
8888 -1 -1 0 1 1000
2468 0001 0004 1 2222 1 500
7777 6666 -1 0 2 300
3721 -1 -1 1 2333 2 150
9012 -1 -1 3 1236 1235 1234 1 100
1235 5678 9012 0 1 50
2222 1236 2468 2 6661 6662 1 300
2333 -1 3721 3 6661 6662 6663 1 100
输出样例:
3
8888 1 1.000 1000.000
0001 15 0.600 100.000
5551 4 0.750 100.000
#include<bits/stdc++.h>
using namespace std;
const int N = 10000;
bool fg[N];
int a[N];
int n, k, id, dad, mom, son, num, sum, ct;
struct node {
int num, sum;
};
map<int, node> mp;
vector<int> v[N];
struct P {
int id, peo;
double avg1, avg2;
P(int a, int b, double c, double d) {
id = a; peo = b; avg1 = c; avg2 = d;
}
bool operator < (const P& p) const {
if (avg2 == p.avg2) return id < p.id;
else return avg2 > p.avg2;
}
};
set<P> st;
int Find(int x) {
if (a[x] < 0) return x;
else return Find(a[x]);
}
void Union(int x, int y) {
int r1 = Find(x);
int r2 = Find(y);
if (r1 < r2) {
a[r1] += a[r2];
a[r2] = r1;
mp[r1].num += mp[r2].num;
mp[r1].sum += mp[r2].sum;
}
else if (r2 < r1) {
a[r2] += a[r1];
a[r1] = r2;
mp[r2].num += mp[r1].num;
mp[r2].sum += mp[r1].sum;
}
}
int main() {
for (int i = 0; i < N; ++i) a[i] = -1;
cin >> n;
for (int i = 0; i < n; ++i) {
cin >> id >> dad >> mom >> k;
v[i].emplace_back(id);
v[i].emplace_back(dad);
v[i].emplace_back(mom);
while (k--) {
cin >> son;
v[i].emplace_back(son);
}
cin >> num >> sum;
mp[id].num = num;
mp[id].sum = sum;
}
for (int i = 0; i < n; ++i) {
id = v[i][0]; fg[id] = 1;
for (int j = 1; j < v[i].size(); ++j) {
if (v[i][j] != -1) { Union(id, v[i][j]); fg[v[i][j]] = 1; }
}
}
for (int i = 0; i < N; ++i) {
if(fg[i])
if (a[i] < 0) {
ct++;
//cout << mp[i].num << ' ' << mp[i].sum << ' ' << i << endl;
st.insert(P(i, -a[i], 1.0 * mp[i].num / (-a[i]), 1.0 * mp[i].sum / (-a[i])));
}
}
printf("%d\n", ct);
for (auto e : st) {
printf("%04d %d %.3lf %.3lf\n", e.id, e.peo, e.avg1, e.avg2);
}
return 0;
}
加班到12点 就是复杂版并查集 主要是他的房子数量 和面积是后面给出来的 就很难受 得先存起来 不然后面mp[id]并查集合并的时候没法。