Merge branch 'youngyangyang04:master' into master

This commit is contained in:
MAX
2024-11-09 19:40:45 -07:00
committed by GitHub
50 changed files with 1885 additions and 128 deletions

View File

@@ -869,6 +869,65 @@ if __name__ == "__main__":
### Javascript
```js
function dijkstra(grid, start, end) {
const visited = Array.from({length: end + 1}, () => false)
const minDist = Array.from({length: end + 1}, () => Number.MAX_VALUE)
minDist[start] = 0
for (let i = 1 ; i < end + 1 ; i++) {
let cur = -1
let tempMinDist = Number.MAX_VALUE
// 1. 找尋與起始點距離最近且未被訪的節點
for (let j = 1 ; j < end + 1 ; j++) {
if (!visited[j] && minDist[j] < tempMinDist) {
cur = j
tempMinDist = minDist[j]
}
}
if (cur === -1) break;
// 2. 更新節點狀態為已拜訪
visited[cur] = true
// 3. 更新未拜訪節點與起始點的最短距離
for (let j = 1 ; j < end + 1 ; j++) {
if(!visited[j] && grid[cur][j] != Number.MAX_VALUE
&& grid[cur][j] + minDist[cur] < minDist[j]
) {
minDist[j] = grid[cur][j] + minDist[cur]
}
}
}
return minDist[end] === Number.MAX_VALUE ? -1 : minDist[end]
}
async function main() {
// 輸入
const rl = require('readline').createInterface({ input: process.stdin })
const iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
const [n, m] = (await readline()).split(" ").map(Number)
const grid = Array.from({length: n + 1},
() => Array.from({length:n + 1}, () => Number.MAX_VALUE))
for (let i = 0 ; i < m ; i++) {
const [s, e, w] = (await readline()).split(" ").map(Number)
grid[s][e] = w
}
// dijkstra
const result = dijkstra(grid, 1, n)
// 輸出
console.log(result)
}
main()
```
### TypeScript
### PhP

View File

@@ -549,6 +549,62 @@ if __name__ == "__main__":
### Javascript
```js
function kruskal(v, edges) {
const father = Array.from({ length: v + 1 }, (_, i) => i)
function find(u){
if (u === father[u]) {
return u
} else {
father[u] = find(father[u])
return father[u]
}
}
function isSame(u, v) {
let s = find(u)
let t = find(v)
return s === t
}
function join(u, v) {
let s = find(u)
let t = find(v)
if (s !== t) {
father[s] = t
}
}
edges.sort((a, b) => a[2] - b[2])
let result = 0
for (const [v1, v2, w] of edges) {
if (!isSame(v1, v2)) {
result += w
join(v1 ,v2)
}
}
console.log(result)
}
async function main() {
const rl = require('readline').createInterface({ input: process.stdin })
const iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
const [v, e] = (await readline()).split(" ").map(Number)
const edges = []
for (let i = 0 ; i < e ; i++) {
edges.push((await readline()).split(" ").map(Number))
}
kruskal(v, edges)
}
main()
```
### TypeScript
### PhP

View File

@@ -693,6 +693,55 @@ if __name__ == "__main__":
### Rust
### Javascript
```js
function prim(v, edges) {
const grid = Array.from({ length: v + 1 }, () => new Array(v + 1).fill(10001)); // Fixed grid initialization
const minDist = new Array(v + 1).fill(10001)
const isInTree = new Array(v + 1).fill(false)
// 建構鄰接矩陣
for(const [v1, v2, w] of edges) {
grid[v1][v2] = w
grid[v2][v1] = w
}
// prim 演算法
for (let i = 1 ; i < v ; i++) {
let cur = -1
let tempMinDist = Number.MAX_VALUE
// 1. 尋找距離生成樹最近的節點
for (let j = 1 ; j < v + 1 ; j++) {
if (!isInTree[j] && minDist[j] < tempMinDist) {
tempMinDist = minDist[j]
cur = j
}
}
// 2. 將節點放入生成樹
isInTree[cur] = true
// 3. 更新非生成樹節點與生成樹的最短距離
for (let j = 1 ; j < v + 1 ; j++) {
if (!isInTree[j] && grid[cur][j] < minDist[j]) {
minDist[j] = grid[cur][j]
}
}
}
console.log(minDist.slice(2).reduce((acc, cur) => acc + cur, 0))
}
async function main() {
const rl = require('readline').createInterface({ input: process.stdin })
const iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
const [v, e] = (await readline()).split(" ").map(Number)
const edges = []
for (let i = 0 ; i < e ; i++) {
edges.push((await readline()).split(" ").map(Number))
}
prim(v, edges)
}
main()
```
### TypeScript

View File

@@ -464,6 +464,60 @@ if __name__ == "__main__":
### Javascript
```js
async function main() {
// 輸入
const rl = require('readline').createInterface({ input: process.stdin })
const iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
const [n, m] = (await readline()).split(" ").map(Number)
const grid = {}
for (let i = 0 ; i < m ; i++) {
const [src, desc, w] = (await readline()).split(" ").map(Number)
if (grid.hasOwnProperty(src)) {
grid[src].push([desc, w])
} else {
grid[src] = [[desc, w]]
}
}
const minDist = Array.from({length: n + 1}, () => Number.MAX_VALUE)
// 起始點
minDist[1] = 0
const q = [1]
const visited = Array.from({length: n + 1}, () => false)
while (q.length) {
const src = q.shift()
const neighbors = grid[src]
visited[src] = false
if (neighbors) {
for (const [desc, w] of neighbors) {
if (minDist[src] !== Number.MAX_VALUE
&& minDist[src] + w < minDist[desc]) {
minDist[desc] = minDist[src] + w
if (!visited[desc]) {
q.push(desc)
visited[desc] = true
}
}
}
}
}
// 輸出
if (minDist[n] === Number.MAX_VALUE) {
console.log('unconnected')
} else {
console.log(minDist[n])
}
}
main()
```
### TypeScript
### PhP

View File

@@ -485,6 +485,45 @@ if __name__ == "__main__":
### Javascript
```js
async function main() {
// 輸入
const rl = require('readline').createInterface({ input: process.stdin })
const iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
const [n, m] = (await readline()).split(" ").map(Number)
const edges = []
for (let i = 0 ; i < m ; i++) {
edges.push((await readline()).split(" ").map(Number))
}
const minDist = Array.from({length: n + 1}, () => Number.MAX_VALUE)
// 起始點
minDist[1] = 0
for (let i = 1 ; i < n ; i++) {
let update = false
for (const [src, desc, w] of edges) {
if (minDist[src] !== Number.MAX_VALUE && minDist[src] + w < minDist[desc]) {
minDist[desc] = minDist[src] + w
update = true
}
}
if (!update) {
break;
}
}
// 輸出
if (minDist[n] === Number.MAX_VALUE) {
console.log('unconnected')
} else {
console.log(minDist[n])
}
}
main()
```
### TypeScript
### PhP

View File

@@ -54,7 +54,7 @@ circle
## 思路
本题是 [kama94.城市间货物运输I](./kama94.城市间货物运输I.md) 延伸题目。
本题是 [kama94.城市间货物运输I](./0094.城市间货物运输I.md) 延伸题目。
本题是要我们判断 负权回路,也就是图中出现环且环上的边总权值为负数。
@@ -64,7 +64,7 @@ circle
接下来我们来看 如何使用 bellman_ford 算法来判断 负权回路。
在 [kama94.城市间货物运输I](./kama94.城市间货物运输I.md) 中 我们讲了 bellman_ford 算法的核心就是一句话:对 所有边 进行 n-1 次松弛。 同时文中的 【拓展】部分, 我们也讲了 松弛n次以上 会怎么样?
在 [kama94.城市间货物运输I](./0094.城市间货物运输I.md) 中 我们讲了 bellman_ford 算法的核心就是一句话:对 所有边 进行 n-1 次松弛。 同时文中的 【拓展】部分, 我们也讲了 松弛n次以上 会怎么样?
在没有负权回路的图中,松弛 n 次以上 ,结果不会有变化。
@@ -72,7 +72,7 @@ circle
那么每松弛一次,都会更新最短路径,所以结果会一直有变化。
(如果对于 bellman_ford 不了解的录友,建议详细看这里:[kama94.城市间货物运输I](./kama94.城市间货物运输I.md)
(如果对于 bellman_ford 不了解的录友,建议详细看这里:[kama94.城市间货物运输I](./0094.城市间货物运输I.md)
以上为理论分析,接下来我们再画图举例。
@@ -94,13 +94,13 @@ circle
如果在负权回路多绕两圈,三圈,无穷圈,那么我们的总成本就会无限小, 如果要求最小成本的话,你会发现本题就无解了。
在 bellman_ford 算法中,松弛 n-1 次所有的边 就可以求得 起点到任何节点的最短路径,松弛 n 次以上minDist数组记录起到到其他节点的最短距离中的结果也不会有改变 (如果对 bellman_ford 算法 不了解,也不知道 minDist 是什么,建议详看上篇讲解[kama94.城市间货物运输I](./kama94.城市间货物运输I.md)
在 bellman_ford 算法中,松弛 n-1 次所有的边 就可以求得 起点到任何节点的最短路径,松弛 n 次以上minDist数组记录起到到其他节点的最短距离中的结果也不会有改变 (如果对 bellman_ford 算法 不了解,也不知道 minDist 是什么,建议详看上篇讲解[kama94.城市间货物运输I](./0094.城市间货物运输I.md)
而本题有负权回路的情况下,一直都会有更短的最短路,所以 松弛 第n次minDist数组 也会发生改变。
那么解决本题的 核心思路,就是在 [kama94.城市间货物运输I](./kama94.城市间货物运输I.md) 的基础上再多松弛一次看minDist数组 是否发生变化。
那么解决本题的 核心思路,就是在 [kama94.城市间货物运输I](./0094.城市间货物运输I.md) 的基础上再多松弛一次看minDist数组 是否发生变化。
代码和 [kama94.城市间货物运输I](./kama94.城市间货物运输I.md) 基本是一样的,如下:(关键地方已注释)
代码和 [kama94.城市间货物运输I](./0094.城市间货物运输I.md) 基本是一样的,如下:(关键地方已注释)
```CPP
#include <iostream>

View File

@@ -51,15 +51,15 @@
## 思路
本题为单源有限最短路问题,同样是 [kama94.城市间货物运输I](./kama94.城市间货物运输I.md) 延伸题目。
本题为单源有限最短路问题,同样是 [kama94.城市间货物运输I](./0094.城市间货物运输I.md) 延伸题目。
注意题目中描述是 **最多经过 k 个城市的条件下而不是一定经过k个城市也可以经过的城市数量比k小但要最短的路径**
在 [kama94.城市间货物运输I](./kama94.城市间货物运输I.md) 中我们讲了:**对所有边松弛一次,相当于计算 起点到达 与起点一条边相连的节点 的最短距离**。
在 [kama94.城市间货物运输I](./0094.城市间货物运输I.md) 中我们讲了:**对所有边松弛一次,相当于计算 起点到达 与起点一条边相连的节点 的最短距离**。
节点数量为n起点到终点最多是 n-1 条边相连。 那么对所有边松弛 n-1 次 就一定能得到 起点到达 终点的最短距离。
(如果对以上讲解看不懂,建议详看 [kama94.城市间货物运输I](./kama94.城市间货物运输I.md)
(如果对以上讲解看不懂,建议详看 [kama94.城市间货物运输I](./0094.城市间货物运输I.md)
本题是最多经过 k 个城市, 那么是 k + 1条边相连的节点。 这里可能有录友想不懂为什么是k + 1来看这个图
@@ -71,7 +71,7 @@
对所有边松弛一次,相当于计算 起点到达 与起点一条边相连的节点 的最短距离,那么对所有边松弛 k + 1次就是求 起点到达 与起点k + 1条边相连的节点的 最短距离。
**注意** 本题是 [kama94.城市间货物运输I](./kama94.城市间货物运输I.md) 的拓展题,如果对 bellman_ford 没有深入了解,强烈建议先看 [kama94.城市间货物运输I](./kama94.城市间货物运输I.md) 再做本题。
**注意** 本题是 [kama94.城市间货物运输I](./0094.城市间货物运输I.md) 的拓展题,如果对 bellman_ford 没有深入了解,强烈建议先看 [kama94.城市间货物运输I](./0094.城市间货物运输I.md) 再做本题。
理解以上内容其实本题代码就很容易了bellman_ford 标准写法是松弛 n-1 次,本题就松弛 k + 1次就好。
@@ -366,19 +366,19 @@ int main() {
## 拓展二(本题本质)
那么前面讲解过的 [94.城市间货物运输I](./kama94.城市间货物运输I.md) 和 [95.城市间货物运输II](./kama95.城市间货物运输II.md) 也是bellman_ford经典算法也没使用 minDist_copy怎么就没问题呢
那么前面讲解过的 [94.城市间货物运输I](./0094.城市间货物运输I.md) 和 [95.城市间货物运输II](./0095.城市间货物运输II.md) 也是bellman_ford经典算法也没使用 minDist_copy怎么就没问题呢
> 如果没看过我上面这两篇讲解的话,建议详细学习上面两篇,再看我下面讲的区别,否则容易看不懂。
[94.城市间货物运输I](./kama94.城市间货物运输I.md) 是没有 负权回路的,那么 多松弛多少次,对结果都没有影响。
[94.城市间货物运输I](./0094.城市间货物运输I.md) 是没有 负权回路的,那么 多松弛多少次,对结果都没有影响。
求 节点1 到 节点n 的最短路径松弛n-1 次就够了,松弛 大于 n-1次结果也不会变。
那么在对所有边进行第一次松弛的时候,如果基于 本次计算的 minDist 来计算 minDist (相当于多做松弛了),也是对最终结果没影响。
[95.城市间货物运输II](./kama95.城市间货物运输II.md) 是判断是否有 负权回路,一旦有负权回路, 对所有边松弛 n-1 次以后,在做松弛 minDist 数值一定会变,根据这一点来判断是否有负权回路。
[95.城市间货物运输II](./0095.城市间货物运输II.md) 是判断是否有 负权回路,一旦有负权回路, 对所有边松弛 n-1 次以后,在做松弛 minDist 数值一定会变,根据这一点来判断是否有负权回路。
所以,[95.城市间货物运输II](./kama95.城市间货物运输II.md) 只需要判断minDist数值变化了就行而 minDist 的数值对不对,并不是我们关心的。
所以,[95.城市间货物运输II](./0095.城市间货物运输II.md) 只需要判断minDist数值变化了就行而 minDist 的数值对不对,并不是我们关心的。
那么本题 为什么计算minDist 一定要基于上次 的 minDist 数值。
@@ -703,6 +703,42 @@ public class Main {
```
### Python
```python
def main():
# 輸入
n, m = map(int, input().split())
edges = list()
for _ in range(m):
edges.append(list(map(int, input().split() )))
start, end, k = map(int, input().split())
min_dist = [float('inf') for _ in range(n + 1)]
min_dist[start] = 0
# 只能經過k個城市所以從起始點到中間有(k + 1)個邊連接
# 需要鬆弛(k + 1)次
for _ in range(k + 1):
update = False
min_dist_copy = min_dist.copy()
for src, desc, w in edges:
if (min_dist_copy[src] != float('inf') and
min_dist_copy[src] + w < min_dist[desc]):
min_dist[desc] = min_dist_copy[src] + w
update = True
if not update:
break
# 輸出
if min_dist[end] == float('inf'):
print('unreachable')
else:
print(min_dist[end])
if __name__ == "__main__":
main()
```
### Go

View File

@@ -277,7 +277,7 @@ ACM格式大家在输出结果的时候要关注看看格式问题特别
有录友可能会想ACM格式就是麻烦有空格没有空格有什么影响结果对了不就行了
ACM模式相对于核心代码模式力扣 更考验大家对代码的掌控能力。 例如工程代码里,输输出都是要自己控制的。这也是为什么大公司笔试都是ACM模式。
ACM模式相对于核心代码模式力扣 更考验大家对代码的掌控能力。 例如工程代码里,输输出都是要自己控制的。这也是为什么大公司笔试都是ACM模式。
以上代码中,结果都存在了 result数组里二维数组每一行是一个结果最后将其打印出来。重点看注释

View File

@@ -499,6 +499,55 @@ main();
### Swift
### Scala
```scala
import scala.collection.mutable.Queue
import util.control.Breaks._
// Dev on LeetCode: https://leetcode.cn/problems/number-of-islands/description/
object Solution {
def numIslands(grid: Array[Array[Char]]): Int = {
val row = grid.length
val col = grid(0).length
val dir = List((-1,0), (0,-1), (1,0), (0,1)) // 四个方向
var visited = Array.fill(row)(Array.fill(col)(false))
var counter = 0
var que = Queue.empty[Tuple2[Int, Int]]
(0 until row).map{ r =>
(0 until col).map{ c =>
breakable {
if (!visited(r)(c) && grid(r)(c) == '1') {
que.enqueue((r, c))
visited(r)(c) // 只要加入队列,立刻标记
} else break // 不是岛屿不进入queue也不记录
while (!que.isEmpty) {
val cur = que.head
que.dequeue()
val x = cur(0)
val y = cur(1)
dir.map{ d =>
val nextX = x + d(0)
val nextY = y + d(1)
breakable {
// 越界就跳过
if (nextX < 0 || nextX >= row || nextY < 0 || nextY >= col) break
if (!visited(nextX)(nextY) && grid(nextX)(nextY) == '1') {
visited(nextX)(nextY) = true // 只要加入队列,立刻标记
que.enqueue((nextX, nextY))
}
}
}
}
counter = counter + 1 // 找完一个岛屿后记录一下
}
}
}
counter
}
}
```
### C#

View File

@@ -412,6 +412,46 @@ const dfs = (graph, visited, x, y) => {
### Swift
### Scala
```scala
import util.control.Breaks._
object Solution {
val dir = List((-1,0), (0,-1), (1,0), (0,1)) // 四个方向
def dfs(grid: Array[Array[Char]], visited: Array[Array[Boolean]], row: Int, col: Int): Unit = {
(0 until 4).map { x =>
val nextR = row + dir(x)(0)
val nextC = col + dir(x)(1)
breakable {
if(nextR < 0 || nextR >= grid.length || nextC < 0 || nextC >= grid(0).length) break
if (!visited(nextR)(nextC) && grid(nextR)(nextC) == '1') {
visited(nextR)(nextC) = true // 经过就记录
dfs(grid, visited, nextR, nextC)
}
}
}
}
def numIslands(grid: Array[Array[Char]]): Int = {
val row = grid.length
val col = grid(0).length
var visited = Array.fill(row)(Array.fill(col)(false))
var counter = 0
(0 until row).map{ r =>
(0 until col).map{ c =>
if (!visited(r)(c) && grid(r)(c) == '1') {
visited(r)(c) = true // 经过就记录
dfs(grid, visited, r, c)
counter += 1
}
}
}
counter
}
}
```
### C#

View File

@@ -222,8 +222,128 @@ public:
## 其他语言版本
### Java
### Java
```java
import java.util.*;
import java.math.*;
/**
* DFS版
*/
public class Main{
static final int[][] dir={{0,1},{1,0},{0,-1},{-1,0}};
static int result=0;
static int count=0;
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
int[][] map = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
map[i][j]=scanner.nextInt();
}
}
boolean[][] visited = new boolean[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if(!visited[i][j]&&map[i][j]==1){
count=0;
dfs(map,visited,i,j);
result= Math.max(count, result);
}
}
}
System.out.println(result);
}
static void dfs(int[][] map,boolean[][] visited,int x,int y){
count++;
visited[x][y]=true;
for (int i = 0; i < 4; i++) {
int nextX=x+dir[i][0];
int nextY=y+dir[i][1];
//水或者已经访问过的跳过
if(nextX<0||nextY<0
||nextX>=map.length||nextY>=map[0].length
||visited[nextX][nextY]||map[nextX][nextY]==0)continue;
dfs(map,visited,nextX,nextY);
}
}
}
```
```java
import java.util.*;
import java.math.*;
/**
* BFS版
*/
public class Main {
static class Node {
int x;
int y;
public Node(int x, int y) {
this.x = x;
this.y = y;
}
}
static final int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
static int result = 0;
static int count = 0;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
int[][] map = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
map[i][j] = scanner.nextInt();
}
}
boolean[][] visited = new boolean[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (!visited[i][j] && map[i][j] == 1) {
count = 0;
bfs(map, visited, i, j);
result = Math.max(count, result);
}
}
}
System.out.println(result);
}
static void bfs(int[][] map, boolean[][] visited, int x, int y) {
Queue<Node> q = new LinkedList<>();
q.add(new Node(x, y));
visited[x][y] = true;
count++;
while (!q.isEmpty()) {
Node node = q.remove();
for (int i = 0; i < 4; i++) {
int nextX = node.x + dir[i][0];
int nextY = node.y + dir[i][1];
if (nextX < 0 || nextY < 0 || nextX >= map.length || nextY >= map[0].length || visited[nextX][nextY] || map[nextX][nextY] == 0)
continue;
q.add(new Node(nextX, nextY));
visited[nextX][nextY] = true;
count++;
}
}
}
}
```
### Python
DFS
@@ -389,6 +509,144 @@ func main() {
### Rust
DFS
``` rust
use std::io;
use std::cmp;
// 定义四个方向
const DIRECTIONS: [(i32, i32); 4] = [(0, 1), (1, 0), (-1, 0), (0, -1)];
fn dfs(grid: &Vec<Vec<i32>>, visited: &mut Vec<Vec<bool>>, x: usize, y: usize, count: &mut i32) {
if visited[x][y] || grid[x][y] == 0 {
return; // 终止条件:已访问或者遇到海水
}
visited[x][y] = true; // 标记已访问
*count += 1;
for &(dx, dy) in DIRECTIONS.iter() {
let new_x = x as i32 + dx;
let new_y = y as i32 + dy;
// 检查边界条件
if new_x >= 0 && new_x < grid.len() as i32 && new_y >= 0 && new_y < grid[0].len() as i32 {
dfs(grid, visited, new_x as usize, new_y as usize, count);
}
}
}
fn main() {
let mut input = String::new();
// 读取 n 和 m
io::stdin().read_line(&mut input);
let dims: Vec<usize> = input.trim().split_whitespace().map(|s| s.parse().unwrap()).collect();
let (n, m) = (dims[0], dims[1]);
// 读取 grid
let mut grid = vec![];
for _ in 0..n {
input.clear();
io::stdin().read_line(&mut input);
let row: Vec<i32> = input.trim().split_whitespace().map(|s| s.parse().unwrap()).collect();
grid.push(row);
}
// 初始化访问记录
let mut visited = vec![vec![false; m]; n];
let mut result = 0;
// 遍历所有格子
for i in 0..n {
for j in 0..m {
if !visited[i][j] && grid[i][j] == 1 {
let mut count = 0;
dfs(&grid, &mut visited, i, j, &mut count);
result = cmp::max(result, count);
}
}
}
// 输出结果
println!("{}", result);
}
```
BFS
```rust
use std::io;
use std::collections::VecDeque;
// 定义四个方向
const DIRECTIONS: [(i32, i32); 4] = [(0, 1), (1, 0), (-1, 0), (0, -1)];
fn bfs(grid: &Vec<Vec<i32>>, visited: &mut Vec<Vec<bool>>, x: usize, y: usize) -> i32 {
let mut count = 0;
let mut queue = VecDeque::new();
queue.push_back((x, y));
visited[x][y] = true; // 标记已访问
while let Some((cur_x, cur_y)) = queue.pop_front() {
count += 1; // 增加计数
for &(dx, dy) in DIRECTIONS.iter() {
let new_x = cur_x as i32 + dx;
let new_y = cur_y as i32 + dy;
// 检查边界条件
if new_x >= 0 && new_x < grid.len() as i32 && new_y >= 0 && new_y < grid[0].len() as i32 {
let new_x_usize = new_x as usize;
let new_y_usize = new_y as usize;
// 如果未访问且是陆地,加入队列
if !visited[new_x_usize][new_y_usize] && grid[new_x_usize][new_y_usize] == 1 {
visited[new_x_usize][new_y_usize] = true; // 标记已访问
queue.push_back((new_x_usize, new_y_usize));
}
}
}
}
count
}
fn main() {
let mut input = String::new();
// 读取 n 和 m
io::stdin().read_line(&mut input).expect("Failed to read line");
let dims: Vec<usize> = input.trim().split_whitespace().map(|s| s.parse().unwrap()).collect();
let (n, m) = (dims[0], dims[1]);
// 读取 grid
let mut grid = vec![];
for _ in 0..n {
input.clear();
io::stdin().read_line(&mut input).expect("Failed to read line");
let row: Vec<i32> = input.trim().split_whitespace().map(|s| s.parse().unwrap()).collect();
grid.push(row);
}
// 初始化访问记录
let mut visited = vec![vec![false; m]; n];
let mut result = 0;
// 遍历所有格子
for i in 0..n {
for j in 0..m {
if !visited[i][j] && grid[i][j] == 1 {
let count = bfs(&grid, &mut visited, i, j);
result = result.max(count);
}
}
}
// 输出结果
println!("{}", result);
}
```
### Javascript
@@ -480,7 +738,84 @@ const bfs = (graph, visited, x, y) => {
})()
```
```javascript
// 深搜版
const r1 = require('readline').createInterface({ input: process.stdin });
// 创建readline接口
let iter = r1[Symbol.asyncIterator]();
// 创建异步迭代器
const readline = async () => (await iter.next()).value;
let graph // 地图
let N, M // 地图大小
let visited // 访问过的节点
let result = 0 // 最大岛屿面积
let count = 0 // 岛屿内节点数
const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]] //方向
// 读取输入,初始化地图
const initGraph = async () => {
let line = await readline();
[N, M] = line.split(' ').map(Number);
graph = new Array(N).fill(0).map(() => new Array(M).fill(0))
visited = new Array(N).fill(false).map(() => new Array(M).fill(false))
for (let i = 0; i < N; i++) {
line = await readline()
line = line.split(' ').map(Number)
for (let j = 0; j < M; j++) {
graph[i][j] = line[j]
}
}
}
/**
* @description: 从(x, y)开始深度优先遍历
* @param {*} graph 地图
* @param {*} visited 访问过的节点
* @param {*} x 开始搜索节点的下标
* @param {*} y 开始搜索节点的下标
* @return {*}
*/
const dfs = (graph, visited, x, y) => {
for (let i = 0; i < 4; i++) {
let nextx = x + dir[i][0]
let nexty = y + dir[i][1]
if(nextx < 0 || nextx >= N || nexty < 0 || nexty >= M) continue
if(!visited[nextx][nexty] && graph[nextx][nexty] === 1){
count++
visited[nextx][nexty] = true
dfs(graph, visited, nextx, nexty)
}
}
}
(async function () {
// 读取输入,初始化地图
await initGraph()
// 统计最大岛屿面积
for (let i = 0; i < N; i++) {
for (let j = 0; j < M; j++) {
if (!visited[i][j] && graph[i][j] === 1) { //遇到没有访问过的陆地
// 重新计算面积
count = 1
visited[i][j] = true
// 深度优先遍历,统计岛屿内节点数,并将岛屿标记为已访问
dfs(graph, visited, i, j)
// 更新最大岛屿面积
result = Math.max(result, count)
}
}
}
console.log(result);
})()
```
### TypeScript

View File

@@ -360,6 +360,71 @@ for i in range(n):
print(count)
```
```python
direction = [[1, 0], [-1, 0], [0, 1], [0, -1]]
result = 0
# 深度搜尋
def dfs(grid, y, x):
grid[y][x] = 0
global result
result += 1
for i, j in direction:
next_x = x + j
next_y = y + i
if (next_x < 0 or next_y < 0 or
next_x >= len(grid[0]) or next_y >= len(grid)
):
continue
if grid[next_y][next_x] == 1 and not visited[next_y][next_x]:
visited[next_y][next_x] = True
dfs(grid, next_y, next_x)
# 讀取輸入值
n, m = map(int, input().split())
grid = []
visited = [[False] * m for _ in range(n)]
for i in range(n):
grid.append(list(map(int, input().split())))
# 處理邊界
for j in range(m):
# 上邊界
if grid[0][j] == 1 and not visited[0][j]:
visited[0][j] = True
dfs(grid, 0, j)
# 下邊界
if grid[n - 1][j] == 1 and not visited[n - 1][j]:
visited[n - 1][j] = True
dfs(grid, n - 1, j)
for i in range(n):
# 左邊界
if grid[i][0] == 1 and not visited[i][0]:
visited[i][0] = True
dfs(grid, i, 0)
# 右邊界
if grid[i][m - 1] == 1 and not visited[i][m - 1]:
visited[i][m - 1] = True
dfs(grid, i, m - 1)
# 計算孤島總面積
result = 0 # 初始化,避免使用到處理邊界時所產生的累加值
for i in range(n):
for j in range(m):
if grid[i][j] == 1 and not visited[i][j]:
visited[i][j] = True
dfs(grid, i, j)
# 輸出孤島的總面積
print(result)
```
### Go
``` go

View File

@@ -178,6 +178,45 @@ int main() {
### Python
```python
father = list()
def find(u):
if u == father[u]:
return u
else:
father[u] = find(father[u])
return father[u]
def is_same(u, v):
u = find(u)
v = find(v)
return u == v
def join(u, v):
u = find(u)
v = find(v)
if u != v:
father[u] = v
if __name__ == "__main__":
# 輸入
n = int(input())
for i in range(n + 1):
father.append(i)
# 尋找冗余邊
result = None
for i in range(n):
s, t = map(int, input().split())
if is_same(s, t):
result = str(s) + ' ' + str(t)
else:
join(s, t)
# 輸出
print(result)
```
### Go
### Rust

View File

@@ -251,8 +251,218 @@ int main() {
### Java
```java
import java.util.*;
/*
* 冗余连接II。主要问题是存在入度为2或者成环也可能两个问题同时存在。
* 1.判断入度为2的边
* 2.判断是否成环(并查集)
*/
public class Main {
/**
* 并查集模板
*/
static class Disjoint {
private final int[] father;
public Disjoint(int n) {
father = new int[n];
for (int i = 0; i < n; i++) {
father[i] = i;
}
}
public void join(int n, int m) {
n = find(n);
m = find(m);
if (n == m) return;
father[n] = m;
}
public int find(int n) {
return father[n] == n ? n : (father[n] = find(father[n]));
}
public boolean isSame(int n, int m) {
return find(n) == find(m);
}
}
static class Edge {
int s;
int t;
public Edge(int s, int t) {
this.s = s;
this.t = t;
}
}
static class Node {
int id;
int in;
int out;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
List<Edge> edges = new ArrayList<>();
Node[] nodeMap = new Node[n + 1];
for (int i = 1; i <= n; i++) {
nodeMap[i] = new Node();
}
Integer doubleIn = null;
for (int i = 0; i < n; i++) {
int s = scanner.nextInt();
int t = scanner.nextInt();
//记录入度
nodeMap[t].in++;
if (!(nodeMap[t].in < 2)) doubleIn = t;
Edge edge = new Edge(s, t);
edges.add(edge);
}
Edge result = null;
//存在入度为2的节点既要消除入度为2的问题同时解除可能存在的环
if (doubleIn != null) {
List<Edge> doubleInEdges = new ArrayList<>();
for (Edge edge : edges) {
if (edge.t == doubleIn) doubleInEdges.add(edge);
if (doubleInEdges.size() == 2) break;
}
Edge edge = doubleInEdges.get(1);
if (isTreeWithExclude(edges, edge, nodeMap)) {
result = edge;
} else {
result = doubleInEdges.get(0);
}
} else {
//不存在入度为2的节点,则只需要解除环即可
result = getRemoveEdge(edges, nodeMap);
}
System.out.println(result.s + " " + result.t);
}
public static boolean isTreeWithExclude(List<Edge> edges, Edge exculdEdge, Node[] nodeMap) {
Disjoint disjoint = new Disjoint(nodeMap.length + 1);
for (Edge edge : edges) {
if (edge == exculdEdge) continue;
//成环则不是树
if (disjoint.isSame(edge.s, edge.t)) {
return false;
}
disjoint.join(edge.s, edge.t);
}
return true;
}
public static Edge getRemoveEdge(List<Edge> edges, Node[] nodeMap) {
int length = nodeMap.length;
Disjoint disjoint = new Disjoint(length);
for (Edge edge : edges) {
if (disjoint.isSame(edge.s, edge.t)) return edge;
disjoint.join(edge.s, edge.t);
}
return null;
}
}
```
### Python
```python
from collections import defaultdict
father = list()
def find(u):
if u == father[u]:
return u
else:
father[u] = find(father[u])
return father[u]
def is_same(u, v):
u = find(u)
v = find(v)
return u == v
def join(u, v):
u = find(u)
v = find(v)
if u != v:
father[u] = v
def is_tree_after_remove_edge(edges, edge, n):
# 初始化并查集
global father
father = [i for i in range(n + 1)]
for i in range(len(edges)):
if i == edge:
continue
s, t = edges[i]
if is_same(s, t): # 成環,即不是有向樹
return False
else: # 將s,t放入集合中
join(s, t)
return True
def get_remove_edge(edges):
# 初始化并查集
global father
father = [i for i in range(n + 1)]
for s, t in edges:
if is_same(s, t):
print(s, t)
return
else:
join(s, t)
if __name__ == "__main__":
# 輸入
n = int(input())
edges = list()
in_degree = defaultdict(int)
for i in range(n):
s, t = map(int, input().split())
in_degree[t] += 1
edges.append([s, t])
# 尋找入度為2的邊並紀錄其下標(index)
vec = list()
for i in range(n - 1, -1, -1):
if in_degree[edges[i][1]] == 2:
vec.append(i)
# 輸出
if len(vec) > 0:
# 情況一:刪除輸出順序靠後的邊
if is_tree_after_remove_edge(edges, vec[0], n):
print(edges[vec[0]][0], edges[vec[0]][1])
# 情況二:只能刪除特定的邊
else:
print(edges[vec[1]][0], edges[vec[1]][1])
else:
# 情況三: 原圖有環
get_remove_edge(edges)
```
### Go
### Rust

View File

@@ -152,66 +152,70 @@ int main() {
## 其他语言版本
### Java
### Java
```Java
import java.util.*;
public class Main {
// BFS方法
public static int ladderLength(String beginWord, String endWord, List<String> wordList) {
// 使用set作为查询容器效率更高
HashSet<String> set = new HashSet<>(wordList);
// 声明一个queue存储每次变更一个字符得到的且存在于容器中的新字符串
Queue<String> queue = new LinkedList<>();
// 声明一个hashMap存储遍历到的字符串以及所走过的路径path
HashMap<String, Integer> visitMap = new HashMap<>();
queue.offer(beginWord);
visitMap.put(beginWord, 1);
while (!queue.isEmpty()) {
String curWord = queue.poll();
int path = visitMap.get(curWord);
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
scanner.nextLine();
String beginStr = scanner.next();
String endStr = scanner.next();
scanner.nextLine();
List<String> wordList = new ArrayList<>();
wordList.add(beginStr);
wordList.add(endStr);
for (int i = 0; i < n; i++) {
wordList.add(scanner.nextLine());
}
int count = bfs(beginStr, endStr, wordList);
System.out.println(count);
}
for (int i = 0; i < curWord.length(); i++) {
char[] ch = curWord.toCharArray();
// 每个位置尝试26个字母
for (char k = 'a'; k <= 'z'; k++) {
ch[i] = k;
String newWord = new String(ch);
if (newWord.equals(endWord)) return path + 1;
// 如果这个新字符串存在于容器且之前未被访问到
if (set.contains(newWord) && !visitMap.containsKey(newWord)) {
visitMap.put(newWord, path + 1);
queue.offer(newWord);
/**
* 广度优先搜索-寻找最短路径
*/
public static int bfs(String beginStr, String endStr, List<String> wordList) {
int len = 1;
Set<String> set = new HashSet<>(wordList);
Set<String> visited = new HashSet<>();
Queue<String> q = new LinkedList<>();
visited.add(beginStr);
q.add(beginStr);
q.add(null);
while (!q.isEmpty()) {
String node = q.remove();
//上一层结束,若下一层还有节点进入下一层
if (node == null) {
if (!q.isEmpty()) {
len++;
q.add(null);
}
continue;
}
char[] charArray = node.toCharArray();
//寻找邻接节点
for (int i = 0; i < charArray.length; i++) {
//记录旧值,用于回滚修改
char old = charArray[i];
for (char j = 'a'; j <= 'z'; j++) {
charArray[i] = j;
String newWord = new String(charArray);
if (set.contains(newWord) && !visited.contains(newWord)) {
q.add(newWord);
visited.add(newWord);
//找到结尾
if (newWord.equals(endStr)) return len + 1;
}
}
charArray[i] = old;
}
}
return 0;
}
public static void main (String[] args) {
/* code */
// 接收输入
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
sc.nextLine();
String[] strs = sc.nextLine().split(" ");
List<String> wordList = new ArrayList<>();
for (int i = 0; i < N; i++) {
wordList.add(sc.nextLine());
}
// wordList.add(strs[1]);
// 打印结果
int result = ladderLength(strs[0], strs[1], wordList);
System.out.println(result);
}
}
```

View File

@@ -375,6 +375,131 @@ for _ in range(n):
### Javascript
```js
class MinHeap {
constructor() {
this.val = []
}
push(val) {
this.val.push(val)
if (this.val.length > 1) {
this.bubbleUp()
}
}
bubbleUp() {
let pi = this.val.length - 1
let pp = Math.floor((pi - 1) / 2)
while (pi > 0 && this.val[pp][0] > this.val[pi][0]) {
;[this.val[pi], this.val[pp]] = [this.val[pp], this.val[pi]]
pi = pp
pp = Math.floor((pi - 1) / 2)
}
}
pop() {
if (this.val.length > 1) {
let pp = 0
let pi = this.val.length - 1
;[this.val[pi], this.val[pp]] = [this.val[pp], this.val[pi]]
const min = this.val.pop()
if (this.val.length > 1) {
this.sinkDown(0)
}
return min
} else if (this.val.length == 1) {
return this.val.pop()
}
}
sinkDown(parentIdx) {
let pp = parentIdx
let plc = pp * 2 + 1
let prc = pp * 2 + 2
let pt = pp // temp pointer
if (plc < this.val.length && this.val[pp][0] > this.val[plc][0]) {
pt = plc
}
if (prc < this.val.length && this.val[pt][0] > this.val[prc][0]) {
pt = prc
}
if (pt != pp) {
;[this.val[pp], this.val[pt]] = [this.val[pt], this.val[pp]]
this.sinkDown(pt)
}
}
}
const moves = [
[1, 2],
[2, 1],
[-1, -2],
[-2, -1],
[-1, 2],
[-2, 1],
[1, -2],
[2, -1]
]
function dist(a, b) {
return ((a[0] - b[0])**2 + (a[1] - b[1])**2)**0.5
}
function isValid(x, y) {
return x >= 1 && y >= 1 && x < 1001 && y < 1001
}
function bfs(start, end) {
const step = new Map()
step.set(start.join(" "), 0)
const q = new MinHeap()
q.push([dist(start, end), start[0], start[1]])
while(q.val.length) {
const [d, x, y] = q.pop()
// if x and y correspond to end position output result
if (x == end[0] && y == end[1]) {
console.log(step.get(end.join(" ")))
break;
}
for (const [dx, dy] of moves) {
const nx = dx + x
const ny = dy + y
if (isValid(nx, ny)) {
const newStep = step.get([x, y].join(" ")) + 1
const newDist = dist([nx, ny], [...end])
const s = step.get([nx, ny].join(" ")) ?
step.get([nx, ny]) :
Number.MAX_VALUE
if (newStep < s) {
q.push(
[
newStep + newDist,
nx,
ny
]
)
step.set([nx, ny].join(" "), newStep)
}
}
}
}
}
async function main() {
const rl = require('readline').createInterface({ input: process.stdin })
const iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
const n = Number((await readline()))
// find min step
for (let i = 0 ; i < n ; i++) {
const [s1, s2, t1, t2] = (await readline()).split(" ").map(Number)
bfs([s1, s2], [t1, t2])
}
}
main()
```
### TypeScript
### PhP