题目
题解
拓扑排序(应该也有其他方法,但对于这类题拓扑是通解)。
本题解对会拓扑和STL的同学比较友好,不会的同学可以去别的博客学习一下,毕竟总会用到的。
在蓝桥杯里,也做过好几个拓扑的题了。
如果你会拓扑,那么这个题难在如何对使用合适的STL保存数据和处理数据。
详细介绍一下代码中变量的含义后,配合代码注释食用最佳。
就是一道拓扑模板题,但是所用数据结构比较麻烦难以理解。
map<string, int> id
:id[str] = c
表示字符串str
的编号为c
,在本题中一个名字对应一个编号,此数据结构用于记录每一个名字的编号是多少。之所以采用编号的思想是因为后面在进行构造拓扑的无向图时会比较方便,而用字符串难以实现;
ids
:每遇到一个没有出现过的字符串,就要为这个字符串设置编号ids
,出现一个新字符串ids++
。用于给字符串编号;
string s1, s2
:输入的字符串;
string ans[N]
:输出拓扑序列就是通过这个函数输出的,即保存答案,ans[i]
排序为i
的字符串是什么;
string nameofid[N]
:编号对应的名字是什么,nameofid[i]
表示编号为i
的名字是什么;
vector<string> name
:全部名字都保存在这里,不重复存;
int ne[M], e[M], h[N], idx
:这几个应该比较熟悉,就是邻接表的几个变量。ne[i]
和e[i]
都表示边的编号为i
对应的点编号,h[i]
表示名字对应编号为i
对应的边编号;
T, n
:如题;
in[N]
:in[i]
表示名字编号为i
对应的入度,拓扑排序中用到;
cnt
:控制ans
数组的个数。这个题目的意思就是必然存在拓扑序列,因此最终ans
的元素数量其实就是出现的字符串的数量,即ids = cnt
。
代码
// https://www.dotcpp.com/oj/problem1506.html
#include<bits/stdc++.h>
using namespace std;
const int N = 110; // 题目说最多13个人,不知道为什么只有开到100+才能不出“运行错误”
const int M = 110;
map<string, int> id;
int ne[M], e[M], h[N], T, n, in[N], cnt, ids, idx;
string s1, s2, ans[N], nameofid[N];
vector<string> name;
void add(int a, int b) { // 传入的参数为名字对应的编号
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void topsort() {
int m = name.size();
queue<string> q; // 元素为名字
for(int i = 0;i < m;i ++) if(in[id[name[i]]] == 0) q.push(name[i]), ans[++cnt] = name[i]; // 将一开始入度为0的名字加入队列和答案数组中
while(!q.empty()) {
string t = q.front();
q.pop();
for(int i = h[id[t]];i != -1;i = ne[i]) { // id[t]为取出的队头名字对应的id,h[id]表示id这个点对应的边
int j = e[i]; // 这是名字的编号
string ss = nameofid[j]; // 编号对应的名字
in[j]--; // 入度--
if(in[j] == 0) q.push(ss), ans[++cnt] = ss; // 入度为0加入队列和答案
}
}
}
int main()
{
cin>>T;
while(T--) {
cin>>n;
// 初始化
id.clear();name.clear();
memset(in, 0, sizeof in);
memset(h, -1, sizeof h);
cnt = 0, idx = 0, ids = 0;
while(n--) {
cin>>s1>>s2;
if(!id[s1]) id[s1] = ++ ids, nameofid[ids] = s1, name.push_back(s1); // 新出现的就ids++
if(!id[s2]) id[s2] = ++ ids, nameofid[ids] = s2, name.push_back(s2);
add(id[s1], id[s2]);
in[id[s2]] ++;
}
topsort();
for(int i = 1;i <= cnt;i ++) cout << ans[i] << ' '; cout<<endl;
}
return 0;
}