110.冗余连接
思路:正着输入 倒着访问。如果访问的这两个元素根相同的话就删除这条边。如果新输入的s和t在集合中已经出现过,说明这条边多余了,可以直接删除。
using namespace std;
#include<iostream>
#include<vector>
vector<int> father(1005,0);
int find(int s){
if(s==father[s]) return s;
else return find(father[s]);
}
void join(int s, int t){
s=find(s);
t=find(t);
if(s==t) return;
father[t]=s;
}
bool issame(int s, int t){
s=find(s);
t=find(t);
return s==t;
}
int main(){
int n,s,t;
cin>>n;
for(int i=0;i<=n;i++){
father[i]=i;
}
for(int i=0;i<n;i++){
cin>>s>>t;
if(issame(s,t)){
cout<<s<<" "<<t;
return 0;
}
else join(s,t);
}
return 0;
}
109.冗余连接II
思路:三种情况 首先是入度为2,一个是两边都可以删,一个是只能删一边,另一个是出现环。怎么判断能不能删:如果碰到将要输入并查集的两个元素已经在并查集里了,说明成环,删错了。先存后面的,这样就先判断的是后面的,后面的不符合条件就删前面的。两边都可以删 删后面那个边。只能删一边 如果符合条件则删这个 不符合删另一个。剩下的细节写在注释里了。写的时候对于每个数组的含义认识比较模糊。
代码:
#include<iostream>
using namespace std;
#include<vector>
int n;
vector<int> father(1005,0);
int find(int s){//找到元素的根
if(s == father[s]) return s;
else return find(father[s]);
}
void init(){//初始化
for(int i=0;i<=n;i++){
father[i]=i;
}
}
bool isSame(int s, int t){//判断两个元素是否属于同一个集合
s = find(s);
t = find(t);
return s == t;
}
void join(int s, int t){//将两个元素放入同一个集合
s = find(s);
t = find(t);
if(s == t) return;
else father[s] = t;
}
bool isTreeAfterRemove(vector<vector<int>> &edges, int deleteedge){//判断删除一条边后是不是树
init();
for(int i=0;i<n;i++){
if(i == deleteedge) continue; //碰到那条边就跳过
if(isSame(edges[i][0],edges[i][1])) return false;
//碰到相等说明都属于一个集合 已经成环 该情况不可以
join(edges[i][0], edges[i][1]);
}
return true;
}
void getRemoveEdge(vector<vector<int>> &edges){//在成环的图中找到需要删除的边
init();
for(int i=0; i < n; i++){
if(isSame(edges[i][0],edges[i][1])){
cout << edges[i][0] << " " << edges[i][1];
return;
}
else join(edges[i][0],edges[i][1]);
}
}
int main(){
init();
cin>>n;
vector<int> inDegree(n+1);
vector<vector<int>> edges;
//计算每个节点的入度
int s,t;
for(int i=0;i<n;i++){
cin >> s >> t;
inDegree[t]++;
edges.push_back({s,t});//存储每一条边
}
vector<int> vec;
//碰到入度为2的点时 存储这两条边
for(int i=n-1;i>=0;i--){//倒序方便访问最后一条边
if(inDegree[edges[i][1]] == 2){//edges[i][1]表示边的终点
vec.push_back(i);
}
}
if(vec.size()>0){
if(isTreeAfterRemove(edges,vec[0])){
cout << edges[vec[0]][0] << " " << edges[vec[0]][1];
return 0;
}
else cout << edges[vec[1]][0] << " " << edges[vec[1]][1];
return 0;
}
getRemoveEdge(edges);
}