1.拓扑排序
我们可以发现,两两的字符串不一样,所以可以把一个字符串转换成一个数字,再把前面的数字指向后面的,这样就构成了拓扑排序,最后只要看拓扑排序是否全部能排出来,即不存在闭合回路就行。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<unordered_map>
#include<queue>
using namespace std;
const int N=1e5+5;
int n,idx;
unordered_map<string,int> id;
vector<int> g[2*N];
int d[2*N];
void solve()
{
cin>>n;
for(int i=1;i<=n;i++){
string a,b;
cin>>a>>b;
if(id[a]==0) id[a]=++idx;
if(id[b]==0) id[b]=++idx;
g[id[a]].push_back(id[b]);
d[id[b]]++;
}
queue<int> q;
for(int i=1;i<=idx;i++){
if(d[i]==0)q.push(i);
}
int cnt=0;
while(!q.empty()){
int u=q.front();q.pop();
cnt++;
for(auto i:g[u]){
if(--d[i]==0){
q.push(i);
}
}
}
if(cnt==idx)cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
int main()
{
solve();
return 0;
}
2.并查集
刚刚上面也说了,我们发现,从前面的字符串指向后面的字符串,因为两两不相同,所以是在一个图里且不存在闭合回路,所以可以用并查集查判环。(别人告诉我这个做法的)
#include <bits/stdc++.h>
#define debug_(x) cerr << #x << " = " << x << ' '
#define debug(x) cerr << #x << " = " << x << '\n'
using namespace std;
typedef long long ll;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
map<string, string> f;
function<string(string)> find = [&](string x) {
if(x == f[x]) return x;
return f[x] = find(f[x]);
};
auto merge = [&](string x, string y) {
if(find(x) == find(y)) return false;
f[f[x]] = f[y];
return true;
};
int n;
cin >> n;
for(int i = 0; i < n; i++) {
string a, b;
cin >> a >> b;
if(f.find(a) == f.end()) f[a] = a;
if(f.find(b) == f.end()) f[b] = b;
if(!merge(a, b)) {
cout << "No\n";
return 0;
}
}
cout << "Yes\n";
return 0;
}