算法训练1-day47-图论

17 阅读3分钟
  1. 108. 多余的边 如果两个节点有着同一个根父节点,那么它们连接成的边就会使得树构成环;因此我们检查输入的两个节点是否在同一集合中,如果是,那么就是冗余边。
#include <iostream>
#include <queue>
#include <unordered_map>
#include <unordered_set>
#include <vector>

using namespace std;

int find(vector<int> &father, int node) {
  if (node == father[node]) {
    return node;
  } else {
    father[node] = find(father, father[node]);
    return father[node];
  }
}

bool join(vector<int> &father, int node1, int node2) {
  int node1Father = find(father, node1);
  int node2Father = find(father, node2);
  if (node1Father == node2Father) {
    return false;
  }
  father[node2Father] = node1Father;
  return true;
}

bool isSameSet(vector<int> &father, int node1, int node2) {
  int node1Father = find(father, node1);
  int node2Father = find(father, node2);
  return node1Father == node2Father;
}

int main() {
  int n = 0;
  cin >> n;

  vector<int> father(n + 1);
  for (int i = 1; i <= n; i++) {
    father[i] = i; // 初始化每个节点的父节点为自己
  }

  int from, to;
  for (int i = 0; i < n; ++i) {
    cin >> from >> to;
    if (!join(father, from, to)) {
      cout << from << " " << to << endl;
      break;
    }
  }

  return 0;
}
  1. 109. 多余的边II
#include<iostream>
#include<vector>
#include<unordered_set>
#include<unordered_map>
#include<queue>

using namespace std;

int find(int v, vector<int>& father)
{
	if (v == father[v]) {
		return v; // 如果父节点是自己,返回当前节点
	}
	return father[v] = find(father[v], father); // 路径压缩,递归查找父节点
}


bool isConnected(int curr, int newVal, vector<int>& father)
{
	curr = find(curr, father); // 查找当前节点的根节点
	newVal = find(newVal, father); // 查找新值的根节点
	return curr == newVal; // 如果两个节点的根节点相同,说明它们在同一集合中
}

void join(int curr, int newVal, vector<int>& father)
{
	curr = find(curr, father); // 查找当前节点的根节点
	newVal = find(newVal, father); // 查找新值的根节点
	if (curr == newVal) return; // 如果两个节点已经在同一集合中,直接返回
	father[newVal] = curr; // 将新值的根节点指向当前节点的根节点,实现合并操作
}


bool isTree(vector<pair<int, int>> edges, int deleteEdge)
{
	vector<int> father(edges.size() + 1);
	for (int i = 1; i <= edges.size(); i++) {
		father[i] = i; // 初始化每个节点的父节点为自己
	}

	for (int i = 0; i < edges.size(); i++) {
		if (i == deleteEdge) continue; // 跳过被删除的边
		int from = edges[i].first;
		int to = edges[i].second;
		if (isConnected(from, to, father)) {
			return false; // 如果已经连通,说明不是树
		}
		join(from, to, father); // 合并两个节点
	}

	return true; // 如果没有重复边,说明是树
}

void cicleCheck(vector<pair<int, int>> edges)
{
	vector<int> father(edges.size() + 1);
	for (int i = 1; i <= edges.size(); i++) {
		father[i] = i; // 初始化每个节点的父节点为自己
	}

	for (int i = 0; i < edges.size(); i++) {
		int from = edges[i].first;
		int to = edges[i].second;
		if (isConnected(from, to, father)) {
			cout << from << " " << to << endl; // 如果已经连通,输出0
			return; // 提前结束程序
		}
		join(from, to, father); // 合并两个节点
	}
}

int main()
{
	int n = 0;
	cin >> n;

	vector<pair<int,int>> edges(n); // 用于存储边的信息

	vector<int> inDegree(n + 1, 0); // 用于记录每个节点的入度
	int from = 0, to = 0;
	for (int i = 0; i < n; i++) {
		cin >> from >> to;
		inDegree[to]++;
		edges[i] = { from, to }; // 存储边的信息
	}

	vector<int> deletedEdges; // 用于存储被删除的边
	for (int i = n - 1; i >= 0; i--) {
		if (inDegree[edges[i].second] == 2) {
			deletedEdges.push_back(i); // 如果度数为2,记录下这条边
		}
	}

	if (deletedEdges.size() > 0) {
		if (isTree(edges, deletedEdges[0])) {
			cout << edges[deletedEdges[0]].first << " " << edges[deletedEdges[0]].second << endl; // 输出被删除的边
		}
		else {
			cout << edges[deletedEdges[1]].first << " " << edges[deletedEdges[1]].second << endl; // 输出被删除的边
		}
		return 0;
	}

	cicleCheck(edges); // 检查是否有环
	return 0;
}