ABC285D Change Usernames
\(\texttt{Description}\)
有 \(n\) 个人,第 \(i\) 个人有名字 \(s_i\) 和理想名字 \(t_i\)。你每次可以将一个人的名字改成理想名字,前提是理想名字目前没人使用。每个人只可以改一次名字。
\(1\le n\le 10^5\),\(s_i\ne t_i\),\(s_i\) 互不相同,\(t_i\) 互不相同。
\(\texttt{Solution}\)
结论:将 \(s_i\) 连边向 \(t_i\),若图无环则有解,否则无解。
证明:若图无环,则在拓扑序中存在出度为 \(0\) 的点,这些点是没人占用的。所以可以按照拓扑排序中的层次从后至前依次更改名字。
否则,每个名字都有人占用,没有人可以让出自己的名字,无解。
因此拓扑判环,遍历的点数是否等于总点数(不是 \(n\))即可。
注意字符串用 map 映射一下。
时间复杂度为 \(\mathcal{O}(n\log_2 n)\),空间复杂度为 \(\mathcal{O}(n)\)。
\(\texttt{Code}\)
$\texttt{Click Here}$
#include<bits/stdc++.h>
#define N 200005//坑点
using namespace std;
int n,rd[N],tot,has,q[10*N],h=1,t=0;
vector<int>g[N];
map<string,int>mp;
string a,b;
int main(){
cin>>n;
for(int i=1;i<=n;++i){
cin>>a>>b;
if(!mp[a]){
mp[a]=++has;
}
if(!mp[b]){
mp[b]=++has;
}
g[mp[a]].push_back(mp[b]);
++rd[mp[b]];
}
for(int i=1;i<=has;++i){
if(!rd[i]){
q[++t]=i;
}
}
while(h<=t){
int u=q[h++];
++tot;
for(int v:g[u]){
if(!--rd[v]){
q[++t]=v;
}
}
}
if(tot^has){
cout<<"No";
}else{
cout<<"Yes";
}
}

浙公网安备 33010602011771号