分析
这道题的本质就是找可以使得每座城市有且仅有一条道单行路进入该市的图有什么特点;
首先,我们假设图联通,则由于每个城市只有一条单行道可以进入,即一个城市必须有且仅有一条单行道与之配对,所以这个图至少要有 n n n条边,即图中必须要有环才可以满足要求!
那如果图不连通了?也很好办,把这个图拆成若干个连通块,每个连通块单独考虑,即每个连通块中必须有环! 这就很好办了,只需要一个带权并查集即可;
再来考虑一下并查集,我们用vis[i]
的真假表示祖先为
i
i
i 的连通块是否有环;则在添边时如果当前边的两个端点早就在同一个连通块中,则把这个连通块的vis
标记为真,如果这条边连接了两个不一样的连通块
(
i
,
j
)
(i,j)
(i,j),则有:
vis[getfather(i)]=vis[getfather(j)]|vis[getfather(i)];
这是因为只要两个连通块中有一个有环,则合并后的大连通块一定包含一个环;
最后就是实现的细节问题了;
Ac Code
#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define int long long
using namespace std;
int father[100005],vis[100005];
int n,m;
int get(int son){
if(father[son]==son){return son;}
return father[son]=get(father[son]);
}
void onion(int x,int y){
int fx=get(x);int fy=get(y);
if(fx==fy){vis[fx]=vis[fy]=1;return;}
father[fx]=fy;
vis[fy]=vis[fx]|vis[fy];
return;
}
signed main(){
scanf("%lld%lld",&n,&m);
for(register int i=1;i<=n;i++){father[i]=i;}
for(register int i=1;i<=m;i++){int x,y;scanf("%lld%lld",&x,&y);onion(x,y);}
for(register int i=1;i<=n;i++){if(!vis[get(i)]){printf("NO\n");return 0;}}
printf("YES\n");return 0;
}