排座位

从1到N编号;M为已知两两宾客之间的关系数;K为查询的条数。随后M行,每行给出一对宾客之间的关系,格式为:宾客1 宾客2 关系,其中关系为1表示是朋友,-1表示是死对头。注意两个人不可能既是朋友又是敌人。最后K行,每行给出一对需要查询的宾客编号,如果两位宾客之间是朋友,且没有敌对关系,则输出No problem;如果他们之间并不是朋友,但也不敌对,则输出OK;如果他们之间有敌对,然而也有共同的朋友,则输出OK but...;如果他们之间只有敌对关系,则输出No way

题解:并查集

首先如果两人之间不可能既是朋友,又是敌人,所以只要判断两人是不是敌对关系,如果是敌对关系我们需要看看有没有共同的朋友,那么我们可以将存在朋友关系的人利用并查集合并到一个集合中,直接查询即可

#include <bits/stdc++.h>
#include <unordered_set>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e2 + 10, M = 4e5 + 10; int n, m, k;
int p[N][N];
int fa[N]; int find(int x)
{
return x == fa[x] ? x : fa[x] = find(fa[x]);
} void merge(int u, int v)
{
u = find(u);
v = find(v);
if (u != v)
fa[u] = v;
} void solve()
{
cin >> n >> m >> k;
for (int i = 1; i <= n; ++i)
fa[i] = i;
for (int i = 1; i <= m; ++i)
{
int u, v, x;
cin >> u >> v >> x;
p[u][v] = p[v][u] = x;
if (x == 1)
merge(u, v);
}
while (k--)
{
int u, v;
cin >> u >> v;
if (p[u][v] == 1)
cout << "No problem" << endl;
else if (p[u][v] == 0)
cout << "OK" << endl;
else if (p[u][v] == -1)
{
if (find(u) == find(v))
cout << "OK but..." << endl;
else
cout << "No way" << endl;
}
}
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

玩转二叉树

给定二叉树的中序遍历和前序遍历,将树做镜面反转后,再输出反转后的层序遍历,镜面反转就是将所有非叶子节点的左右孩子互换

题解:二叉树的遍历

我们发现镜面反转无非是先遍历右儿子再遍历左儿子

我们再考虑如何根据二叉树的中序遍历和前序遍历来输出层序遍历:

  • 首先中序遍历是左根右的顺序,前序遍历是根左右的顺序,我们模拟过程尝试递归解决该问题

我们发现我们可以递归解决该问题:因为根节点一定是前序遍历的第一个点,我们只要在中序遍历中找到根节点,然后我们就知道了左子树和右子树相对应的前序遍历和中序遍历,因为前序遍历和中序遍历长度一定是一样的,我们可以从中序遍历的长度反推出前序遍历的长度

那么输出层序遍历就是用数组存储二叉树,注意左儿子和右儿子存放的位置应该交换

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 2e5 + 10, M = 4e5 + 10; int n;
int tree[N];
int pre[N]; // 前序遍历
int in[N]; // 中序遍历 void dfs(int rt_index, int l, int r, int id)
{
if (l > r)
return;
int rt = pre[rt_index];
tree[id] = rt;
int p = 0;
for (int i = l; i <= r; ++i)
if (in[i] == rt)
{
p = i;
break;
}
dfs(rt_index + 1, l, p - 1, id * 2 + 1);
dfs(rt_index + p - l + 1, p + 1, r, id * 2);
} void solve()
{
memset(tree, -1, sizeof tree);
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> in[i];
for (int i = 1; i <= n; ++i)
cin >> pre[i];
dfs(1, 1, n, 1);
int cnt = 0;
for (int i = 1; cnt < n; i++)
{
if (tree[i] != -1)
{
cout << tree[i] << " ";
cnt++;
}
}
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

关于堆的判断

将一系列给定数字顺序插入一个初始为空的小顶堆H[]。随后判断一系列相关命题是否为真。命题分下列几种:

  • x is the rootx是根结点;
  • x and y are siblingsxy是兄弟结点;
  • x is the parent of yxy的父结点;
  • x is a child of yxy的一个子结点;
  • 对输入的每个命题,如果其为真,则在一行中输出T,否则输出F

题解:模拟堆:\(O(nlogn)\)

根据题意我们模拟小根堆,我们将所有的数插入堆\(O(nlogn)\)后利用哈希表记录每个数字在数组上下标的映射,然后\(O(1)\)回答询问即可



int n, q;
int idx;
int h[N];
unordered_map<int, int> mp; void down(int u)
{
int t = u;
if (u * 2 <= idx && h[u * 2] < h[t])
t = u * 2;
if (u * 2 + 1 <= idx && h[u * 2 + 1] < h[t])
t = u * 2 + 1;
if (t != u)
{
swap(h[t], h[u]);
down(t);
}
} void up(int u)
{
while (u / 2 && h[u / 2] > h[u])
{
swap(h[u / 2], h[u]);
u /= 2;
}
} void solve()
{
cin >> n >> q;
for (int i = 1; i <= n; ++i)
{
int x;
cin >> x;
h[++idx] = x;
up(idx);
}
for (int i = 1; i <= n; ++i)
mp[h[i]] = i;
while (q--)
{
string s;
int x, y;
cin >> x;
cin >> s;
if (s == "and")
{
cin >> y;
cin >> s >> s;
if (mp[x] / 2 == mp[y] / 2)
cout << "T" << endl;
else
cout << "F" << endl;
}
else
{
cin >> s;
if (s == "a")
{
cin >> s >> s >> y;
if (mp[x] / 2 == mp[y])
cout << "T" << endl;
else
cout << "F" << endl;
}
else
{
cin >> s;
if (s == "root")
{
if (mp[x] == 1)
cout << "T" << endl;
else
cout << "F" << endl;
}
else
{
cin >> s >> y;
if (mp[y] / 2 == mp[x])
cout << "T" << endl;
else
cout << "F" << endl;
}
}
}
}
}

天梯地图

输入在第一行给出两个正整数N(2 ≤ N ≤ 500)和M,分别为地图中所有标记地点的个数和连接地点的道路条数。随后M行,每行按如下格式给出一条道路的信息:

V1 V2 one-way length time

其中V1V2是道路的两个端点的编号(从0到N-1);如果该道路是从V1V2的单行线,则one-way为1,否则为0;length是道路的长度;time是通过该路所需要的时间。最后给出一对起点和终点的编号。

输出格式:

首先按下列格式输出最快到达的时间T和用节点编号表示的路线:

Time = T: 起点 => 节点1 => ... => 终点

然后在下一行按下列格式输出最短距离D和用节点编号表示的路线:

Distance = D: 起点 => 节点1 => ... => 终点

如果最快到达路线不唯一,则输出几条最快路线中最短的那条,题目保证这条路线是唯一的。而如果最短距离的路线不唯一,则输出途径节点数最少的那条,题目保证这条路线是唯一的。

如果这两条路线是完全一样的,则按下列格式输出:

Time = T; Distance = D: 起点 => 节点1 => ... => 终点

题解:单源最短路求方案 + 多种限制

显然我们需要跑两个不同的\(dij\),一个用来求出最短距离,一个用来求出最短时间,我们考虑如何记录方案,显然我们可以记录一个点的前驱,所以不妨借用\(dp\)的思想开个\(pre\)前驱数组来记录每次的转移

那么方案的问题解决了,我们考虑题目给出的限制已经在这个限制上我们状态怎么转移

  1. 最短距离的基础上求经过的点最少,显然我们的前驱数组的\(size\)就是经过的点数,如果最短距离相同的情况下,我们比较一下前驱数组的大小,选择小的转移即可
  2. 最短时间的基础上求经过的距离最短,我们同时还需要一个\(dis\)数组,和最短时间一起同步更新,如果下一个点在最短时间相同的情况下,我们比较一下\(dis[v]>dis[u] + w\)即可
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 5e2 + 10, M = 4e5 + 10; int n, m;
vector<array<int, 3>> g[N];
int d1[N], d2[N]; vector<int> dij1(int st, int ed) // 时间
{
for (int i = 0; i < n; ++i)
d1[i] = INF;
vector<int> pre[N];
vector<int> vis(n + 10);
vector<int> dis(n + 10);
d1[st] = 0;
priority_queue<pii, vector<pii>, greater<pii>> q;
q.push({d1[st], st});
while (q.size())
{
int u = q.top().second;
q.pop();
if (vis[u])
continue;
vis[u] = 1;
for (auto &[v, w1, w2] : g[u])
{
if (d1[v] > d1[u] + w1)
{
d1[v] = d1[u] + w1;
dis[v] = dis[u] + w2; //同步更新
pre[v] = pre[u];
pre[v].push_back(u);
q.push({d1[v], v});
}
else if (d1[v] == d1[u] + w1 && dis[v] > dis[u] + w2)
{
pre[v] = pre[u];
pre[v].push_back(u);
}
}
}
pre[ed].push_back(ed);
return pre[ed];
} vector<int> dij2(int st, int ed) // 距离
{
for (int i = 0; i < n; ++i)
d2[i] = INF;
vector<int> pre[N];
vector<int> vis(n + 10);
d2[st] = 0;
priority_queue<pii, vector<pii>, greater<pii>> q;
q.push({d2[st], st});
while (q.size())
{
int u = q.top().second;
q.pop();
if (vis[u])
continue;
vis[u] = 1;
for (auto &[v, w1, w2] : g[u])
{
if (d2[v] > d2[u] + w2)
{
d2[v] = d2[u] + w2;
pre[v] = pre[u];
pre[v].push_back(u);
q.push({d2[v], v});
}
else if (d2[v] == d2[u] + w2 && pre[v].size() > pre[u].size() + 1)
{
pre[v] = pre[u];
pre[v].push_back(u);
}
}
}
pre[ed].push_back(ed);
return pre[ed];
} void solve()
{
cin >> n >> m;
for (int i = 1; i <= m; ++i)
{
int u, v, flag, len, time;
cin >> u >> v >> flag >> len >> time;
if (flag)
{
g[u].push_back({v, time, len});
}
else
{
g[u].push_back({v, time, len});
g[v].push_back({u, time, len});
}
}
int st, ed;
cin >> st >> ed;
auto ans1 = dij1(st, ed);
auto ans2 = dij2(st, ed);
if (ans1 == ans2)
{
cout << "Time = " << d1[ed] << "; Distance = " << d2[ed] << ": ";
for (int i = 0; i < ans1.size(); i++)
{
if (i != 0)
cout << " => ";
cout << ans1[i];
}
cout << endl;
}
else
{
cout << "Time = " << d1[ed] << ": ";
for (int i = 0; i < ans1.size(); i++)
{
if (i != 0)
cout << " => ";
cout << ans1[i];
}
cout << endl;
cout << "Distance = " << d2[ed] << ": ";
for (int i = 0; i < ans2.size(); i++)
{
if (i != 0)
cout << " => ";
cout << ans2[i];
}
cout << endl;
}
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

随机推荐

  1. IntelliJ Idea 常用快捷键参照列表

    IntelliJ Idea 常用快捷键参照列表 Ctrl+Shift + Enter,语句完成 "!",否定完成,输入表达式时按 "!"键 Ctrl+E,最近的 ...

  2. ASP.NET Core C# 反射 & 表达式树 (第三篇)

    前言 前一篇讲完了反射, 这一篇来讲一下和反射息息相关的表达式树. 首先搞清楚 Delegate, Action, Func, Anonymous Method, Lambda, Expression ...

  3. SpringMVC——SSM整合——项目异常处理

    项目异常处理 项目异常分类 业务异常 不规范的用户行为产生的异常    规范的用户行为产生的异常    系统异常 项目运行过程中可预计且无法避免的异常    其他异常 编程人员未预期到的异常    项 ...

  4. socket close和shutdown的区别,TIME_WAIT和CLOSE_WAIT

    TCP主动关闭连接 appl: close(), --> FIN FIN_WAIT_1 //主动关闭socket方,调用close关闭socket,发FIN               < ...

  5. 11-02 NOIP练习赛

    11-02 NOIP练习赛 为什么休息的天还要打练习赛,这不公平!!!!!!!!!! oh no! 但是三道题确实挺简单,也少见的很有意思. [USACO23OPEN] Milk Sum S 题面翻译 ...

  6. 五行强度得分_喜用神api免费接口_json数据八字五行强弱接口

    本API接口基于深厚的八字学原理,为用户提供详尽的五行(金.木.水.火.土)强弱分析.五行打分评估,以及精准的喜用神判断.用户只需输入自己的八字信息,即可获得全面而深入的命理解读. ‌一.核心功能‌ ...

  7. 诸葛测字在线测算免费api接口_json格式数据返回

    ‌诸葛测字是一种古老的占卜术,相传是由三国时代的诸葛亮所创.‌ 诸葛测字通过选取三个汉字,计算其笔画数,然后根据这些数字对照特定的歌诀或表格来预测吉凶.解答疑惑.这种方法强调心诚手净,焚香祷告,通过三 ...

  8. 活动预告 | 中国数据库联盟(ACDU)中国行第二站定档杭州,邀您探讨数据库技术与实践!

    数据库技术一直是信息时代中不可或缺的核心组成部分,随着信息量的爆炸式增长和数据的多样化,其重要性愈发凸显.作为中国数据库联盟(ACDU)的品牌活动之一,[ACDU 中国行]在线下汇集数据库领域的行业知 ...

  9. MYSQL存储过程-练习1

    MYSQL存储过程-练习1 创建book表 CREATE TABLE `book` ( `boodid` int unsigned NOT NULL AUTO_INCREMENT, `bookname ...

  10. .NET 7+Vue 3 开源仓库管理系统 ModernWMS

    前言 本系统的设计目标是帮助中小企业乃至大型企业实现仓库操作的自动化与数字化,从而提升工作效率,降低成本,并最终实现业务增长.项目采用 Vue 3 + TS + .NET 7 等前沿框架进行开发,为企 ...