KamaCoder 107. 寻找存在的路径
题目:107. 寻找存在的路径 (kamacoder.com)
题解:代码随想录 (programmercarl.com)
solution
class Program
{
public static void Main(string[] args)
{
string[] dimensions = Console.ReadLine().Split();
int n = int.Parse(dimensions[0]);
int m = int.Parse(dimensions[1]);
DSU dsu = new DSU(n);
for (int i = 0; i < m; i++)
{
string[] nums = Console.ReadLine().Split();
int x = int.Parse(nums[0]) - 1;
int y = int.Parse(nums[1]) - 1;
dsu.union(x, y);
}
string[] nodes = Console.ReadLine().Split();
Console.WriteLine(dsu.find(int.Parse(nodes[0]) - 1) == dsu.find(int.Parse(nodes[1]) - 1) ? 1 : 0);
}
}
class DSU
{
int[] dsu;
public DSU(int size)
{
dsu= new int[size];
for (int i = 0; i < size; i++)
{
dns[i] = i;
}
}
public int find(int num)
{
if (dsu[num] != num)
{
dsu[num] = find(dsu[num]);
}
return dsu[num];
}
public void union(int x, int y)
{
int rootx = find(x);
int rooty = find(y);
if (rootx != rooty)
{
dsu[rootx] = y;
}
}
}
KamaCoder 108. 冗余连接
solution
class Program
{
public static void Main(string[] args)
{
int num1 = 0;
int num2 = 0;
string N = Console.ReadLine();
int n = int.Parse(N);
DSU dsu = new DSU(n);
for (int i = 0; i < n; i++)
{
string[] nums = Console.ReadLine().Split();
int x = int.Parse(nums[0]) - 1;
int y = int.Parse(nums[1]) - 1;
if (dsu.union(x, y))
{
num1 = x;
num2 = y;
}
}
Console.WriteLine(string.Join(" ", num1 + 1, num2 + 1));
}
}
class DSU
{
int[] dsu;
public DSU(int size)
{
dsu = new int[size];
for (int i = 0; i < size; i++)
{
dsu[i] = i;
}
}
public int find(int num)
{
if (dsu[num] != num)
{
dsu[num] = find(dsu[num]);
}
return dsu[num];
}
public bool union(int x, int y)
{
int rootx = find(x);
int rooty = find(y);
if (rootx != rooty)
{
dsu[rootx] = y;
return false;
}
else return true;
}
}
summary
key:
(成环)删除的边:构成边的两个节点具有相同的根
改造union函数:遇到需要删除的边则记录节点,否则将边加入并查集
KamaCoder 107. 冗余连接Ⅱ
题目:109. 冗余连接II (kamacoder.com)
题解:代码随想录 (programmercarl.com)
solution
class Program
{
public static void Main(string[] args)
{
//处理输入
// 维度
string N = Console.ReadLine();
int n = int.Parse(N);
// 数组
int[][] edges = new int[n + 1][];
for (int i = 1; i <= n; i++)
{
string[] nodes = Console.ReadLine().Split();
edges[i][0] = int.Parse(nodes[0]);
edges[i][1] = int.Parse(nodes[1]);
}
//初始化
// 可能的双父节点
int[] candi1 = null;
int[] candi2 = null;
// dsu数组
DSU dsu = new DSU(n + 1);
//检查双父节点并拆分
foreach (int[] edge in edges)
{
int parent = edge[0];
int child = edge[1];
if (dsu.dsu[child] != child)
{
// 原边
candi1 = new int[] { dsu.dsu[child], child };
// 新边
candi2 = new int[] { parent, child };
// 拆分
edge[1] = 0;
}
else
{
dsu.dsu[child] = parent;
}
}
//检查环
// 重新初始化
for (int i = 0; i <= n; i++)
{
dsu.dsu[i] = i;
}
foreach (int[] edge in edges)
{
if (edge[1] == 0) continue;
int parent = edge[0];
int child = edge[1];
if (!dsu.union(parent, child))
{
if (candi1 == null)
{
Console.WriteLine($"{parent} {child}");
}
else
{
Console.WriteLine($"{candi1[0]} {candi2[1]}");
}
return;
}
}
Console.WriteLine($"{candi2[0]} {candi2[1]}");
}
}
public class DSU
{
public int[] dsu;
public DSU(int size)
{
dsu = new int[size];
for (int i = 0; i < size; i++)
{
dsu[i] = i;
}
}
public int find(int num)
{
if (dsu[num] != num)
{
dsu[num] = find(dsu[num]);
}
return dsu[num];
}
public bool union(int x, int y)
{
int rootx = find(x);
int rooty = find(y);
if (rootx == rooty) return false;
else
{
dsu[y] = x;
return true;
}
}
}
summary
两种冗余情况:
1、一个节点存在两个父节点
2、存在环
清除冗余策略:
1、记录每个节点的父节点,如果存在则分别记录两条边
2、使用并查集检测环
3、判断情况:
若不存在双父节点:直接处理环
若存在双父节点:分别尝试删除两条边