2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「電脳少女プログラミング2088 | 壊レタ君を再構築」をKotlinでやってみた

Last updated at Posted at 2025-01-25

「電脳少女プログラミング2088 | 壊レタ君を再構築」をKotlinでやってみた (途中) ので、公開したいと思います。

途中ですが、進んだら更新していきたいと思います。
また、解説は後で書くかもしれませんが、ランクD相当は書かないと思います。

郊外のスラム街(paizaランク:D相当)

fun main() {
    val n = readLine()!!.toInt()
    println(n / 2 + 100)
}

カジノ(paizaランク:D相当)

fun main() {
    val dollar01 = readLine()!!.toInt()
    val dollar05 = readLine()!!.toInt()
    val dollar10 = readLine()!!.toInt()
    println(dollar01 + 5 * dollar05 + 10 * dollar10)
}

ネオン街の裏路地(paizaランク:D相当)

private fun readInt(): Int = readLine()!!.toInt()

fun main() {
    val n = readInt()
    val max = (0 until n).map { readInt() }.maxBy { it }
    println(max)
}

自然の残る公園(paizaランク:C相当)

private fun line(): String = readLine()!!

fun main() {
    val (n,cx, cy) = line().split(' ').map { it.toInt() }
    val nearNo = (1..n)
        .map {
            val (x, y) = line().split(" ").map { it.toInt() }
            val l = (x-cx)*(x-cx) + (y-cy)*(y-cy)
            it to l
        }
        .minBy { (_, l) -> l }
        .first
    println(nearNo)
}

ネオン街のクラブ(paizaランク:C相当)

kotlinはランキングに関係していないようですが、除外します。

廃マンションの一室(paizaランク:C相当)

import kotlin.math.abs

fun main() {
    val n = readLine()!!.toInt()
    var w = n
    var i = 0
    // 10進で10桁MAXとするなら3進で21桁ぐらい?(log 10^10 / log 3 ≒ = 21?)
    val t = IntArray(size = 21)
    do {
        val d = w % 3
        w /= 3
        when (val v = d + t[i]) {
            // 3は桁を上げる
            3 -> {
                t[i] = 0 // 元の桁は0
                t[i + 1] = 1 // +1として桁を上げる
            }
            // 2は桁を上げて-1したこととする
            2 -> {
                t[i] = -1 // -1する
                t[i + 1] = 1 // +1として桁を上げる
            }
            // そのまま
            1, 0, -1 -> t[i] = v
            // -2は桁を上げて+1したこととする
            -2 -> {
                t[i] = 1 // +1する
                t[i + 1] = -1 // -1として桁を上げる
            }
            // -3は桁を上げる
            -3 -> {
                t[i] = 0 // 元の桁は0
                t[i + 1] = -1 // -1として桁を上げる
            }
            // エラー
            else -> error("n=$n, i=$i, w=$w, d=$d, t[i]=${t[i]}, v=$v")
        }
        i++
    } while (abs(w) > 0 && i in t.indices)
    // 表示を修正して特殊3進数の文字列作成
    val text = t.reversed().dropWhile { it == 0 }.joinToString(separator = "") {
        when (it) {
            -1 -> "2"
            0 -> "0"
            1 -> "1"
            else -> error("Illegal value=$it")
        }
    }.ifEmpty { "0" } // 少し手抜き
    println(text)
}

この辺からローカルで試しながらでないと難しかった。

ギャングのアジト(paizaランク:B相当)

private fun line(): String = readLine()!!

fun main() {
    val n = line().toInt()
    for(i in 1..n) {
        val l = line()
        val r = l.reversed()
        if(l != r) {
            println("No")
            return
        }
    }
    println("Yes")
}

手抜きです…。

private fun line(): String = readLine()!!

fun main() {
    val n = line().toInt()
    for(i in 1..n) {
        val l = line().split(" ").map { it.toInt() }
        val nor = l.take(n / 2)
        val rev = l.reversed().take(n / 2)
        if(nor != rev) {
            println("No")
            return
        }
    }
    println("Yes")
}

一応、あまり手抜きではないものです。

一番通りの繁華街(paizaランク:B相当)

private const val TERRITORY = '.'

private class Grid(private val width: Int, private val grid: List<Char>) {
    init {
        require(grid.size == width * width)
    }

    operator fun get(point: Point): Char? = get(point.x, point.y)
    operator fun get(x: Int, y: Int): Char? =
        if (x in 0 until width &&
            y in 0 until width
        ) {
            grid[y * width + x]
        } else {
            null
        }
}

private data class Point(val x: Int, val y: Int)

private fun MutableSet<Set<Point>>.addIfTerritory(base: Point, diagonal: Point, g: Grid) {
    val point2 = Point(diagonal.x, base.y)
    val point3 = Point(base.x, diagonal.y)
    if (g[base] == TERRITORY &&
        g[point2] == TERRITORY &&
        g[diagonal] == TERRITORY &&
        g[point3] == TERRITORY
    ) {
        add(setOf(base, point2, diagonal, point3))
    }
}

private fun territoriesCount(width: Int, grid: List<Char>): Int {
    val g = Grid(width, grid)
    val territories = mutableSetOf<Set<Point>>()
    for (x in 0 until width) {
        for (y in 0 until width) {
            val point = Point(x, y)
            if (g[point] != TERRITORY) continue
            for (dw in 1 until width) {
                territories.addIfTerritory(point, Point(x + dw, y + dw), g)
                territories.addIfTerritory(point, Point(x - dw, y - dw), g)
                territories.addIfTerritory(point, Point(x - dw, y + dw), g)
                territories.addIfTerritory(point, Point(x + dw, y - dw), g)
            }
        }
    }
    return territories.size
}

private fun line(): String = readLine()!!

fun main() {
    val n = line().toInt()
    val grid = (0 until n).map { line().toCharArray() }.flatMap { it.toList() }
    println(territoriesCount(n, grid).toString())
}

この問題もローカルで試しながら行った。
テリトリーとなる正方形を4つの位置のSetとして扱って、更にSetを使って何種類になるのかをカウントしている。

新都心のハイウェイ(paizaランク:A相当)

private const val CAR_A: Int = 0
private const val CAR_B: Int = -1
private const val GOAL: Int = -2
private const val WALL: Int = Int.MIN_VALUE
private val EMPTY: Int? = null

private class Cells(val h: Int, val w: Int, val cells: MutableList<Int?>) {
    operator fun get(x: Int, y: Int): Int? =
        if (x in 0 until w && y in 0 until h) {
            cells[y * w + x]
        } else {
            WALL // 範囲外は壁として扱う
        }

    operator fun set(x: Int, y: Int, value: Int?) {
        cells[y * w + x] = value
    }
}

private tailrec fun setupGoalInner(cells: Cells, x: Int, y: Int, dx: Int, dy: Int) {
    if (cells[x + dx, y + dy] != WALL) {
        cells[x + dx, y + dy] = GOAL
        setupGoalInner(cells, x = x + dx, y = y + dy, dx = dx, dy = dy)
    }
}

private fun setupGoal(cells: Cells) {
    // Bの位置を探す
    val indexB = cells.cells.indexOfFirst { it == CAR_B }
    val carBx = indexB % cells.w
    val carBy = indexB / cells.w
    // Bの位置から十字にゴール判定で埋める
    setupGoalInner(cells, carBx, carBy, dx = 1, dy = 0)
    setupGoalInner(cells, carBx, carBy, dx = -1, dy = 0)
    setupGoalInner(cells, carBx, carBy, dx = 0, dy = 1)
    setupGoalInner(cells, carBx, carBy, dx = 0, dy = -1)
}

private tailrec fun foundCarB(cells: Cells, step: Int): Int {
    var assigned = false
    for (y in 0 until cells.h) {
        for (x in 0 until cells.w) {
            if (cells[x, y] != step) continue
            assigned = true
            // ゴールに到達していたら終了
            if (cells[x + 1, y] == GOAL) return step + 1
            if (cells[x - 1, y] == GOAL) return step + 1
            if (cells[x, y + 1] == GOAL) return step + 1
            if (cells[x, y - 1] == GOAL) return step + 1
            // 次の移動ステップを代入
            if (cells[x + 1, y] == EMPTY) cells[x + 1, y] = step + 1
            if (cells[x - 1, y] == EMPTY) cells[x - 1, y] = step + 1
            if (cells[x, y + 1] == EMPTY) cells[x, y + 1] = step + 1
            if (cells[x, y - 1] == EMPTY) cells[x, y - 1] = step + 1
        }
    }
    // 代入がなかったら見つからないとして終了
    if (assigned.not()) return -1
    // 次
    return foundCarB(cells, step = step + 1)
}

private fun foundCarB(cells: Cells): Int {
    // Aの位置を取得
    val indexA = cells.cells.indexOfFirst { it == CAR_A }
    val carAx = indexA % cells.w
    val carAy = indexA / cells.w
    // ゴールを設定
    setupGoal(cells)
    // Aの位置のゴールチェック
    if (cells[carAx, carAy] == GOAL) return 0
    // 探す
    return foundCarB(cells, step = 0)
}

private fun line(): String = readLine()!!

fun main() {
    val (h, w) = line().split(" ").map { it.toInt() }
    val cells = (0 until h).map { line().toCharArray() }.flatMap { it.toList() }.map {
        when (it) {
            'A' -> CAR_A
            'B' -> CAR_B
            '#' -> WALL
            '.' -> EMPTY
            else -> error("Invalid cell: $it")
        }
    }.let { Cells(h, w, it.toMutableList()) }
    println(foundCarB(cells))
}

最初は、経路が見つからなかったときの処理を作成しなかったため、無限ループにしてしまっていました。
Aが移動する移動数を代入していく形をベースに求めようとしています。
指摘内容としては、効率が良くないようです。
そのうち、他の方の投稿なども見てみたいと思います。

思い出の屋上(paizaランク:S相当)

import kotlin.math.abs
import kotlin.math.max

private val EMPTY: Int? = null

private class Area(val h: Int, val w: Int) {
    val cells: MutableList<Int?> = MutableList(size = h * w) { EMPTY }

    operator fun get(row: Int, col: Int): Int? =
        if (row in 1..h && col in 1..w) {
            cells[(row - 1) * w + (col - 1)]
        } else {
            EMPTY // 範囲外は空として扱う
        }

    operator fun set(row: Int, col: Int, value: Int?) {
        check(this[row, col] == EMPTY) { "Already set. row=$row, col=$col, ${this[row, col]}" }
        if (row in 1..h && col in 1..w) {
            cells[(row - 1) * w + (col - 1)] = value
        }
    }

    override fun toString(): String {
        return buildString {
            for (row in 1..h) {
                for (col in 1..w) {
                    append(
                        when (val c = this@Area[row, col]) {
                            EMPTY -> '.'
                            else -> c!!.toString(radix = 16).last()
                        }
                    )
                }
                appendLine()
            }
        }
    }
}

private fun setupTerritory(area: Area, row: Int, col: Int, distance: Int) {
    for (dCol in -distance..distance) {
        val rowDistance = distance - abs(dCol)
        for (dRow in 0..rowDistance) {
            if (dRow == 0) {
                area[row, col + dCol] = distance
            } else {
                area[row + dRow, col + dCol] = distance
                area[row - dRow, col + dCol] = distance
            }
        }
    }
}

private fun canEstablishTerritory(area: Area, row: Int, col: Int): Int? {
    if (area[row, col] != EMPTY) return null
    val maxDistance = max(area.h, area.w)
    for (distance in 0..maxDistance) {
        for (dCol in -distance..distance) {
            val rowDistance = distance - abs(dCol)
            if (rowDistance == 0) {
                if (area[row, col + dCol] != EMPTY) return distance - 1
            } else {
                if (area[row + rowDistance, col + dCol] != EMPTY) return distance - 1
                if (area[row - rowDistance, col + dCol] != EMPTY) return distance - 1
            }
        }
    }
    return maxDistance
}

private fun findMaxTerritorySize(area: Area): Int =
    (1..area.h).flatMap { row -> (1..area.w).map { col -> Pair(row, col) } }
        .mapNotNull { (row, col) -> canEstablishTerritory(area, row = row, col = col) }
        .maxOrNull() ?: -1

private fun line(): String = readLine()!!

fun main() {
    val (h, w, m) = line().split(" ").map { it.toInt() }
    val area = Area(h, w)
    (1..m).map { line() }
        .map { line -> line.split(" ").map { it.toInt() } }
        .forEach { (row, col, distance) ->
            setupTerritory(area, row = row, col = col, distance = distance)
        }
    println(findMaxTerritorySize(area))
}

この問題もローカルで試しながら行った。


コツコツやってきましたが、プログラムの問題は全部記載したので、本投稿は終了です。
気が向けば解説の追記などを書くかもしれません。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?