Day53-图论,卡码网110,105,106
- 岛屿的周长
-
题目描述:给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿是被水包围,并且通过水平方向或垂直方向上相邻的陆地连接而成的。
-
你可以假设矩阵外均被水包围。在矩阵中恰好拥有一个岛屿,假设组成岛屿的陆地边长都为 1,请计算岛屿的周长。岛屿内部没有水域。
-
输入描述:第一行包含两个整数 N, M,表示矩阵的行数和列数。之后 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。
-
输出描述:输出一个整数,表示岛屿的周长。
-
输入示例
-
5 5
-
0 0 0 0 0
-
0 1 0 1 0
-
0 1 1 1 0
-
0 1 1 1 0
-
0 0 0 0 0
-
输出示例
-
14
- 思路
const r1 = require('readline').createInterface({ input: process.stdin });
let iter = r1[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
let graph // 地图
let N, M // 地图大小
// 读取输入,初始化地图
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))
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]
}
}
}
(async function () {
// 读取输入,初始化地图
await initGraph()
let sum = 0 // 陆地数量
let cover = 0 // 相邻数量
for (let i = 0; i < N; i++) {
for (let j = 0; j < M; j++) {
if (graph[i][j] == 1) {
sum++ // 统计总到陆地数
// 统计上边相邻陆地
if(i - 1 >= 0 && graph[i-1][j] == 1) cover++
// 统计左边相邻陆地
if (j - 1 >= 0 && graph[i][j-1] == 1) cover++
// 不统计下边和右边,因为避免重复计算
}
}
}
console.log(sum * 4 - cover * 2);
})()
const r1 = require('readline').createInterface({ input: process.stdin });
let iter = r1[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
let graph // 地图
let N, M // 地图大小
// 读取输入,初始化地图
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))
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]
}
}
}
(async function () {
// 读取输入,初始化地图
await initGraph()
let dir = [[0,1], [1,0], [-1, 0], [0, -1]]
let result = 0
for (let i = 0; i < N; i++) {
for (let j = 0; j < M; j++) {
if (graph[i][j] == 1) {
for (let k = 0; k < 4; k++ ) { // 上下左右四个方向
// 计算周边坐标
let x = i + dir[k][0]
let y = j + dir[k][1]
// x在边界上 || y在边界上 || x,y位置是水域
if(x < 0 || x >= N || y < 0 || y >= M || graph[x][y] == 0) {
result++
}
}
}
}
}
console.log(result);
})()
- 字符串接龙
-
题目描述:字典 strList 中从字符串 beginStr 和 endStr 的转换序列是一个按下述规格形成的序列:
-
- 序列中第一个字符串是 beginStr。
-
- 序列中最后一个字符串是 endStr。
-
- 每次转换只能改变一个字符。
-
- 转换过程中的中间字符串必须是字典 strList 中的字符串,且strList里的每个字符串只用使用一次。
-
给你两个字符串 beginStr 和 endStr 和一个字典 strList,找到从 beginStr 到 endStr 的最短转换序列中的字符串数目。如果不存在这样的转换序列,返回 0。
-
输入描述:第一行包含一个整数 N,表示字典 strList 中的字符串数量。 第二行包含两个字符串,用空格隔开,分别代表 beginStr 和 endStr。 后续 N 行,每行一个字符串,代表 strList 中的字符串。
-
输出描述:输出一个整数,代表从 beginStr 转换到 endStr 需要的最短转换序列中的字符串数量。如果不存在这样的转换序列,则输出 0。
-
输入示例
-
6
-
abc def
-
efc
-
dbc
-
ebc
-
dec
-
dfc
-
yhn
-
输出示例
-
4
-
提示:从 startStr 到 endStr,在 strList 中最短的路径为 abc -> dbc -> dec -> def,所以输出结果为 4
- 思路
const r1 = require('readline').createInterface({ input: process.stdin });
// 创建readline接口
let iter = r1[Symbol.asyncIterator]();
// 创建异步迭代器
const readline = async () => (await iter.next()).value;
let N //输入字符串个数
let beginStr //开始字符串
let endStr //结束字符串
let strSet = new Set() //字符串集合
let visitedMap = new Map() //访问过的字符串
// 读取输入,初始化地图
const init = async () => {
let line = await readline();
line = line.trim()
N = Number(line);
line = await readline();
line = line.trim().split(' ')
beginStr = line[0]
endStr = line[1]
for (let i = 0; i < N; i++) {
line = await readline()
line = line.trim()
strSet.add(line.trim())
}
}
(async function () {
// 读取输入,初始化数据
await init()
// 初始化队列
let queue = []
queue.push(beginStr)
// 初始化visitMap
visitedMap.set(beginStr, 1)
while (queue.length) {
let word = queue.shift()
let path = visitedMap.get(word)
// 遍历26个字母
for (let i = 0; i < word.length; i++) {
let newWord = word.split('') // 用一个新字符串替换str,因为每次要置换一个字符
for (let j = 0; j < 26; j++) {
newWord[i] = String.fromCharCode('a'.charCodeAt() + j)
// 发现替换字母后,字符串与终点字符串相同
if (newWord.join('') === endStr) {
console.log(path + 1);
return 0; // 找到了路径
}
// 字符串集合里出现了newWord,并且newWord没有被访问过
if (strSet.has(newWord.join('')) && !visitedMap.has(newWord.join(''))) {
// 添加访问信息,并将新字符串放到队列中
queue.push(newWord.join(''))
visitedMap.set(newWord.join(''), path + 1)
}
}
}
}
console.log(0);
})()
- 有向图的完全联通
- 题目描述:给定一个有向图,包含 N 个节点,节点编号分别为 1,2,...,N。现从 1 号节点开始,如果可以从 1 号节点的边可以到达任何节点,则输出 1,否则输出 -1。
- 输入描述:第一行包含两个正整数,表示节点数量 N 和边的数量 K。 后续 K 行,每行两个正整数 s 和 t,表示从 s 节点有一条边单向连接到 t 节点。
- 输出描述:如果可以从 1 号节点的边可以到达任何节点,则输出 1,否则输出 -1。
- 输入示例
- 4 4
- 1 2
- 2 1
- 1 3
- 2 4
- 输出示例
- 1
- 思路
- 深搜三部曲
-
- 确认递归函数,参数dfs(graph, key, visited),需要传入地图,需要知道当前我们拿到的key,以至于去下一个房间。同时还需要一个数组,用来记录我们都走过了哪些房间,这样好知道最后有没有把所有房间都遍历的,可以定义一个一维数组。
-
- 确认终止条件
-
- 处理目前搜索节点出发的路径
/**
* 1. 输入处理
* 功能:通过 readline 逐行读取输入,存储到 inputLines 数组。
* 输入格式:
第一行:n edgesCount(节点总数 n,边数 edgesCount)
后续行:from to(每条边的起点和终点)
* 2. 构建图的邻接表
* 邻接表:
graph 是一个长度为 n+1 的数组(节点编号从1开始)。
graph[from] 存储从 from 出发能直接到达的节点列表。
* 3. 深度优先搜索(DFS)
* 功能:从节点1出发,递归标记所有可达节点。
* visited 数组:
初始化全为 false。
DFS 过程中,访问过的节点标记为 true。
* 递归逻辑:
1. 如果当前节点已访问,直接返回。
2. 标记当前节点为已访问。
3. 遍历当前节点的所有邻居,递归调用 DFS。
* 4. 连通性检查
* 检查:遍历所有节点(1到n),如果存在未被访问的节点:
输出 -1(表示从节点1无法到达所有节点)。
否则输出 1(表示可以到达所有节点)。
*/
const rl = require('readline').createInterface({
input:process.stdin,
output:process.stdout
})
let inputLines = []
rl.on('line' , (line)=>{
inputLines.push(line)
})
rl.on('close',()=>{
let [n , edgesCount]= inputLines[0].trim().split(' ').map(Number)
let graph = Array.from({length:n+1} , ()=>{return[]})
for(let i = 1 ; i < inputLines.length ; i++ ){
let [from, to] = inputLines[i].trim().split(' ').map(Number)
graph[from].push(to)
}
let visited = new Array(n + 1).fill(false)
let dfs = (graph , key , visited)=>{
if(visited[key]){
return
}
visited[key] = true
for(let nextKey of graph[key]){
dfs(graph,nextKey , visited)
}
}
dfs(graph , 1 , visited)
for(let i = 1 ; i <= n;i++){
if(visited[i] === false){
console.log(-1)
return
}
}
console.log(1)
})
参考&感谢各路大神
宝剑锋从磨砺出,梅花香自苦寒来。

浙公网安备 33010602011771号