团体程序设计天梯赛-练习集 L2 (练习中)
题解目录
目录
L2题单
进度 | 标号 | 标题 | 涉及的算法 |
---|---|---|---|
L2-001 | 紧急救援 | 图论 , dijkstra + dfs | |
L2-002 | 链表去重 | 模拟 + 链表 | |
L2-003 | 月饼 | 完全背包 | |
L2-004 | 这是二叉搜索树吗? | 二叉树遍历 | |
✔ | L2-005 | 集合相似度 | 集合 |
L2-006 | 树的遍历 | 二叉树遍历 | |
L2-007 | 家庭房产 | 并查集 + 排序 | |
✔ | L2-008 | 最长对称子串 | DP |
L2-009 | 抢红包 | 排序 | |
L2-010 | 排座位 | 并查集 | |
L2-011 | 玩转二叉树 | 二叉树遍历 | |
L2-012 | 关于堆的判断 | 堆 + 字符串 | |
L2-013 | 红色警报 | 并查集 | |
✔ | L2-014 | 列车调度 | 单调队列, set lower_bound的运用 |
L2-015 | 互评成绩 | 排序 | |
✔ | L2-016 | 愿天下有情人都是失散多年的兄妹 | 并查集 + DFS |
L2-017 | 人以群分 | 排序 | |
L2-018 | 多项式A除以B | 高精度 | |
✔ | L2-019 | 悄悄关注 | 哈希 |
L2-020 | 功夫传人 | 二叉树遍历 | |
L2-021 | 点赞狂魔 | 哈希 + 排序 | |
L2-022 | 重排链表 | 链表 + 模拟 | |
✔ | L2-023 | 图着色问题 | 图论, 染色 |
✔ | L2-024 | 部落 | 并查集 |
✔ | L2-025 | 分而治之 | 图论 + 枚举 |
L2-026 | 小字辈 | 二叉树遍历 | |
L2-027 | 名人堂与代金券 | 排序 | |
L2-028 | 秀恩爱分得快 | 字符串 + 枚举 | |
L2-029 | 特立独行的幸福 | 数论 + 模拟 | |
L2-030 | 冰岛人 | LCA + BFS/DFS | |
L2-031 | 深入虎穴 | 二叉树遍历 | |
L2-032 | 彩虹瓶 | 栈混洗 | |
L2-033 | 简单计算器 | 栈 | |
L2-034 | 口罩发放 | 大模拟 + 排序 | |
✔ | L2-035 | 完全二叉树的层序遍历 | 二叉树遍历 |
L2-036 | 网红点打卡攻略 | 图论, 哈密尔顿环路 | |
L2-037 | 包装机 | 模拟 | |
L2-038 | 病毒溯源 | 二叉树遍历 | |
✔ | L2-039 | 清点代码库 | 哈希 + 排序 |
L2-040 | 哲哲打游戏 | 大模拟 | |
L2-041 | 插松枝 | 模拟 + 队列/栈 | |
✔ | L2-042 | 老板的作息表 | 排序 |
L2-043 | 龙龙送外卖 | 树 + 图论 | |
✔ | L2-044 | 大众情人 | 图论, Floyd |
题解
L2-005 集合相似度
超时....每次询问都重新构建set, 一开始就应该用set数组存所有集合
#include<iostream>
#include<unordered_set>
using namespace std;
const int N = 51, M = 1e4+10;
int a[N][M];
int main()
{
int n;
cin >> n;
for(int i = 1; i <= n; ++i){
scanf("%d", &a[i][0]);
for(int j = 1; j <= a[i][0]; ++j) scanf("%d", &a[i][j]);
}
int x, y, t;
cin >> t;
while(t --){
scanf("%d%d", &x, &y);
unordered_set<int> s1;
unordered_set<int> s2;
int same_num = 0;
for(int i = 1; i <= a[x][0]; ++i) s1.insert(a[x][i]);
for(int i = 1; i <= a[y][0]; ++i) s2.insert(a[y][i]);
for(auto t : s1)
if(s2.count(t))
++same_num;
double res = (1.0)*same_num/(s1.size()+s2.size()-same_num)*100;
printf("%.2f\%\n", res);
}
return 0;
}
修改后
#include<iostream>
#include<unordered_set>
using namespace std;
const int N = 51;
unordered_set<int> s[N];
int main()
{
int n, m, x;
cin >> n;
for(int i = 1; i <= n; ++i){
scanf("%d", &m);
for(int j = 0; j < m; ++j) {
scanf("%d", &x);
s[i].insert(x);
}
}
int a, b, t;
cin >> t;
while(t --){
scanf("%d%d", &a, &b);
int same_num = 0;
for(auto t : s[b])
if(s[a].count(t))
++same_num;
double res = (1.0)*same_num/(s[a].size()+s[b].size()-same_num)*100;
printf("%.2f\%\n", res);
}
return 0;
}
L2-008 最长对称子串
st[i][j]: 区间[i, j]之间的字符串是否是回文串
st[i][j] = (s[i] == s[j]) && st[i-1][j-1]
res = max{所有长度区间}
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1010;
bool st[N][N];
char s[N];
int main()
{
scanf("%[^\n]", s);
//cin.get(s, N);
int res = 1;
int len = strlen(s);
for(int i = 0; i < len; ++i) st[i][i] = true;
for(int i = 0; i < len-1; ++i)
if(s[i] == s[i+1])
st[i][i+1] = true, res = 2;
for(int j = 3; j <= len; ++j)
for(int i = 0; i+j-1 < len; ++i)
{
int k = i+j-1;
if(s[i] == s[k] && st[i+1][k-1]) {
st[i][k] = true;
res = max(res, j);
}
}
cout << res;
return 0;
}
L2-014 列车调度
要使列车出来的序列倒序, 那么当序列号为x的列车刚刚要进隧道,
-
如果之前已经出现过比x大的号, 则x可以选择一个比他大的号(可能不止一个比他大) 所在的隧道, 此时那个比他大的号会被移除, 为了使每个隧道的号尽可能紧凑, 我们选择的是比他大的号里面最小的那个号所在的隧道, 并把那个数移除(为了保证set的大小就是隧道数量)
-
如果之前没出现过比x大的号就新开一个隧道(set的大小就是隧道数量)
#include<iostream>
#include<set>
using namespace std;
set<int> headlist;
int main()
{
int n, x;
cin >> n;
for(int i = 0; i < n; ++i){
cin >> x;
set<int>::iterator t = headlist.lower_bound(x);
if(t != headlist.end()) headlist.erase(t);
headlist.insert(x);
}
cout << headlist.size();
return 0;
}
L2-016 愿天下有情人都是失散多年的兄妹
- 并查集 + dfs
#include<iostream>
using namespace std;
const int N = 1e5+10;
struct people{
int f, m;
int gender;
people():f(-1), m(-1), gender(-1){}
}p[N];
bool find(int a, int b, int u){
if(u == 5 || a == -1 || b == -1) return true;
if(a == b) return false;
return find(p[a].f, p[b].f, u+1) && find(p[a].f, p[b].m, u+1) &&
find(p[a].m, p[b].f, u+1) && find(p[a].m, p[b].m, u+1);
}
int main()
{
int n;
cin >> n;
int id, fid, mid;
char g;
while(n --){
cin >> id >> g >> fid >> mid;
p[id].gender = (g == 'M' ? 1 : 0);
p[id].f = fid, p[id].m = mid;
p[fid].gender = fid == -1 ? -1 : 1;
p[mid].gender = mid == -1 ? -1 : 0;
}
cin >> n;
while(n --){
int a, b;
cin >> a >> b;
if(p[a].gender == p[b].gender) cout << "Never Mind\n";
else {
bool ret = find(a, b, 0);
if(ret) cout << "Yes\n";
else cout << "No\n";
}
}
return 0;
}
L2-019 悄悄关注
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
map<string, int> focus_mp;
map<string, int> unfocus_mp;
vector<string> v;
int main()
{
int n, m;
cin >> n;
string s;
for(int i = 0; i < n; ++i){
cin >> s;
focus_mp[s] = 0;
}
cin >> m;
int cnt, num = 0;
for(int i = 0; i < m; ++i){
cin >> s >> cnt;
num += cnt;
if(focus_mp.find(s) != focus_mp.end()) focus_mp[s] = cnt;
else unfocus_mp[s] = cnt;
}
double avg = num/m;
for(auto t : unfocus_mp)
if(t.second > avg)
v.push_back(t.first);
if(v.size()){
sort(v.begin(), v.end());
for(auto t : v) cout << t << "\n";
}else cout << "Bing Mei You";
return 0;
}
L2-023 图着色问题
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
const int N = 510;
int col[N], col_st[N];
vector<int> e[N];
int main()
{
int n, m, k;
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);
}
int t;
cin >> t;
while(t--)
{
memset(col_st, 0, sizeof col_st);
int col_cnt = 0;
for(int i = 1; i <= n; ++i) {
cin >> col[i];
if(!col_st[col[i]]){
col_st[col[i]] = 1;
++col_cnt;
}
}
if(col_cnt != k) {
cout << "No" << endl;
continue;
}
bool ret = true;
for(int i = 1; i <= n; ++i){
int len = e[i].size();
for(int j = 0; j < len; ++j){
if(col[e[i][j]]==col[i]){
ret = false;
break;
}
}
if(!ret) break;
}
if(ret) cout << "Yes" << endl;
else cout << "No" << endl;
}
return 0;
}
L2-024 部落
- 并查集
#include<iostream>
#include<set>
using namespace std;
const int N = 1e4+10;
int f[N], st[N];
set<int> header_set;
int find(int x){
if(x != f[x]) f[x] = find(f[x]);
return f[x];
}
void unite(int a, int b){
int fa = find(a), fb = find(b);
if(fa != fb) f[fa] = fb;
}
int main()
{
int k, q;
cin >> k;
while(k --)
{
int n, h, x;
cin >> n >> h;
if(!st[h]) f[h] = h, st[h] = 1;
for(int i = 1; i < n; ++i){
cin >> x;
if(!st[x]) f[x] = x, st[x] = 1;
unite(h, x);
}
}
int cnt = 0;
for(int i = 1; i <= 10000; ++i){
if(st[i]){
++cnt;
header_set.insert(find(i));
}
}
cout << cnt << " " << header_set.size() << "\n";
cin >> q;
while(q --)
{
int a, b;
cin >> a >> b;
int fa = find(a), fb = find(b);
if(fa != fb) cout << "N\n";
else cout << "Y\n";
}
return 0;
}
L2-025 分而治之
-
图论, 模拟
-
管理好图的出入度即可
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e4+10, M = 2e4+10;
int n, m;
int h[N], in[N], backup_in[N];
int e[M], ne[M], idx;
void add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int main()
{
memset(h, -1, sizeof h);
scanf("%d%d", &n, &m);
int a, b;
for(int i = 0; i < m; ++i){
scanf("%d%d", &a, &b);
++in[a], ++in[b];
add(a, b), add(b, a);
}
// for(int i = 1; i <= n; ++i) printf("in[%d]: %d\n", i, in[i]);
int t, tt, x;
scanf("%d", &t);
while(t --)
{
scanf("%d", &tt);
for(int i = 1; i <= n; ++i) backup_in[i] = in[i];
for(int i = 0; i < tt; ++i){
scanf("%d", &x);
for(int j = h[x]; ~j; j = ne[j]){
int u = e[j];
--backup_in[x], --backup_in[u];
}
}
bool ret = true;
for(int i = 1; i <= n; ++i){
if(backup_in[i] > 0){
ret = false;
break;
}
}
if(ret) printf("YES\n");
else printf("NO\n");
}
return 0;
}
L2-035 完全二叉树的层序遍历
#include<iostream>
using namespace std;
const int N = 110;
int n;
int post[N], tree[N], idx;
void build(int u){
if(u > n) return ;
build(u << 1), build(u << 1 | 1);
tree[u] = post[idx++];
}
int main()
{
cin >> n;
for(int i = 0; i < n; ++i) cin >> post[i];
build(1);
for(int i = 1; i <= n; ++i) {
cout << tree[i];
if(i != n) cout << " ";
}
return 0;
}
L2-039 清点代码库
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
const int N = 10010;
map<vector<int>, int> vec2key;
map<int, vector<int>> key2vec;
vector<int> v[N];
int idx;
struct Example{
int num = 0;
int key;
}e[N];
bool cmp(Example a, Example b){
if(a.num == b.num) return key2vec[a.key] < key2vec[b.key];
else return a.num > b.num;
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
int x;
for(int i = 0; i < n; ++i){
for(int j = 0; j < m; ++j){
scanf("%d", &x);
v[i].push_back(x);
}
}
for(int i = 0; i < n; ++i)
{
if(vec2key.find(v[i]) != vec2key.end())
e[vec2key[v[i]]].num++;
else {
vec2key[v[i]] = ++idx;
key2vec[idx] = v[i];
e[idx].num = 1;
e[idx].key = idx;
}
}
sort(e+1, e+idx+1, cmp);
printf("%d\n", idx);
for(int i = 1; i <= idx; ++i)
{
printf("%d", e[i].num);
vector<int> t = key2vec[e[i].key];
for(auto j : t) printf(" %d", j);
printf("\n");
}
return 0;
}
L2-042 老板的作息表
- 自定义排序, 模拟
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 220000;
struct TimeNode{
int l, r;
bool operator < (struct TimeNode& b) const{
if(l != b.l) return l < b.l;
return r < b.r;
}
}tn[N];
int time2num(int h, int m, int s){
return h*3600+m*60+s;
}
void num2time(int t1, int t2){
int h1 = t1/3600, h2 = t2/3600;
t1 %= 3600, t2 %= 3600;
int m1 = t1/60, m2 = t2/60;
t1 %= 60, t2 %= 60;
int s1 = t1, s2 = t2;
printf("%02d:%02d:%02d - %02d:%02d:%02d\n", h1, m1, s1, h2, m2, s2);
}
int main()
{
int n;
cin >> n;
int h1, h2, m1, m2, s1, s2;
for(int i = 0; i < n; ++i){
scanf("%d:%d:%d - %d:%d:%d", &h1, &m1, &s1, &h2, &m2, &s2);
tn[i] = {time2num(h1,m1,s1), time2num(h2,m2,s2)};
}
sort(tn, tn+n);
int pre = 0;
for(int i = 0; i < n; ++i){
if(tn[i].l > pre) num2time(pre, tn[i].l);
pre = tn[i].r;
}
int end = time2num(23,59,59);
if(pre != end) num2time(pre, end);
return 0;
}
L2-044 大众情人
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 510, INF = 0x3f3f3f3f;
int d[N][N], g[N];
int mx[N]; //mx[i]: 其他异性到i的距离最大值
int main()
{
int n, m;
cin >> n;
memset(d, 0x3f, sizeof d);
for(int i = 1; i <= n; ++i) d[i][i] = 0;
char gender;
int b, c;
for(int i = 1; i <= n; ++i){
cin >> gender >> m;
g[i] = gender=='M';
for(int j = 0; j < m; ++j){
scanf("%d:%d", &b, &c);
d[i][b] = c;
}
}
//floyd
for(int k = 1; k <= n; ++k)
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
d[i][j] = min(d[i][j], d[i][k]+d[k][j]);
for(int k = 0; k < 2; ++k) //k: 0->女 ; 1->男
{
int mi = INF; //得到当前性别(K)的mx[]最小值
for(int i = 1; i <= n; ++i){
if(g[i] == k) {
for(int j = 1; j <= n; ++j)
if(g[j] != k)
mx[i] = max(mx[i], d[j][i]);
mi = min(mi, mx[i]);
}
}
vector<int> v; //只来控制最后输出的格式, (pta真傻呗)
for(int i = 1; i <= n; ++i)
if(g[i] == k && mx[i] == mi)
v.push_back(i);
for(int i = 0; i < v.size(); ++i){
if(i) cout << " ";
cout << v[i];
}
cout << '\n';
}
return 0;
}
本文来自博客园,作者:泥烟,CSDN同名, 转载请注明原文链接:https://www.cnblogs.com/Knight02/p/pta-L2.html