寻找存在的路径
这题使用并查集即可。并查集加路径压缩。
cpp
#include <iostream>
using namespace std;
int find(int* father,int u){
return father[u] == u ? u : father[u] = find(father,father[u]);
}
bool isSame(int* father,int u,int v){
return find(father,u) == find(father,v);
}
void join(int* father,int u,int v){
u = find(father,u);
v = find(father,v);
if(u == v){
return;
}
father[v] = u;
}
int main(){
int N,M,source,destination,u,v;
cin >> N >> M;
int father[N+1];
for(int i=1;i<=N;i++){
father[i] = i;
}
for(int i=0;i<M;i++){
cin >> u >> v;
join(father,u,v);
}
cin >> source >> destination;
if(isSame(father,source,destination)){
cout<<1;
}
else{
cout<<0;
}
}
冗余连接
这题也是并查集问题,删除那个导致图存在环的边,我们可以通过判断新加入的边的两个点是否存在同一个father,如果他们是同一个father,那就说明这两个点是已经加入图中的点,如果在这两个点之间加一条边的话会导致环的产生。而如果是新加入图的点那他们的祖先应该是不同的。
cpp
#include <iostream>
using namespace std;
int N;
int father[1001];
void init(){
for(int i=1;i<=N;i++){
father[i] = i;
}
}
int find(int u){
return father[u] == u ? u : father[u] = find(father[u]);
}
bool isSame(int u,int v){
return find(u) == find(v);
}
void join(int u,int v){
u = find(u);
v = find(v);
if(u == v) return;
father[v] = u;
}
int main(){
int u,v;
cin >> N;
init();
for(int i=0;i<N;i++){
cin >> u >> v;
if(isSame(u,v)){
printf("%d %d",u,v);
break;
}
else{
join(u,v);
}
}
}
冗余连接II
这道题与上题逻辑类似,不过他变成了有向图,这里需要判断删除的边是否能继续保证图变成有向树即除了根节点,其余的节点的入度都得是1且不存在环。所以我们需要收集那些入度为2的节点,并尝试去删除其中的边,使有向图变成一个有向树。
cpp
#include <iostream>
#include <vector>
using namespace std;
int N;
int father[1001];
void init(){
for(int i=1;i<=N;i++){
father[i] = i;
}
}
int find(int u){
return father[u] == u ? u : father[u] = find(father[u]);
}
bool isSame(int u,int v){
return find(u) == find(v);
}
void join(int u,int v){
u = find(u);
v = find(v);
if(u == v) return;
father[v] = u;
}
void getRemoveEdge(vector<vector<int>>& edges){
init();
for(vector<int>& v : edges){
if(isSame(v[0],v[1])){
printf("%d %d",v[0],v[1]);
return;
}
else{
join(v[0],v[1]);
}
}
}
bool isTreeAfterRemoveEdges(vector<vector<int>> &edges,int deleteEdge){
init();
for(int i=0;i<edges.size();i++){
if(i==deleteEdge) continue;
if(isSame(edges[i][0],edges[i][1])){
return false;
}
join(edges[i][0],edges[i][1]);
}
return true;
}
int main(){
int u,v;
vector<vector<int>> edges;
cin >> N;
vector<int> inDegrees(N+1,0);
for(int i=0;i<N;i++){
cin >> u >> v;
inDegrees[v]++;
edges.push_back({u,v});
}
vector<int> vec;
for(int i = N-1;i>=0;i--){
if(inDegrees[edges[i][1]] == 2){
vec.push_back(i);
}
}
if(vec.size()>0){
if(isTreeAfterRemoveEdges(edges,vec[0])){
printf("%d %d",edges[vec[0]][0],edges[vec[0]][1]);
}
else{
printf("%d %d",edges[vec[1]][0],edges[vec[1]][1]);
}
return 0;
}
getRemoveEdge(edges);
}