Day53-图论,卡码网110,105,106

  1. 岛屿的周长
  • 题目描述:给定一个由 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);
})()


  1. 字符串接龙
  • 题目描述:字典 strList 中从字符串 beginStr 和 endStr 的转换序列是一个按下述规格形成的序列:

    1. 序列中第一个字符串是 beginStr。
    1. 序列中最后一个字符串是 endStr。
    1. 每次转换只能改变一个字符。
    1. 转换过程中的中间字符串必须是字典 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);
})()


  1. 有向图的完全联通
  • 题目描述:给定一个有向图,包含 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

  • 思路
  • 深搜三部曲
    1. 确认递归函数,参数dfs(graph, key, visited),需要传入地图,需要知道当前我们拿到的key,以至于去下一个房间。同时还需要一个数组,用来记录我们都走过了哪些房间,这样好知道最后有没有把所有房间都遍历的,可以定义一个一维数组。
    1. 确认终止条件
    1. 处理目前搜索节点出发的路径
/**
 * 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)

})



参考&感谢各路大神

posted @ 2025-07-19 07:32  安静的嘶吼  阅读(3)  评论(0)    收藏  举报