1
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?

Advent of Code 2025 Day 12: Christmas Tree Farm をRustで解いた

1
Last updated at Posted at 2025-12-15

Advent of Code

毎日2題出題されます。競技プログラミングチックに楽しめます。

この問題概要と実装解答を以下にご紹介します。
問題概要は生成AIに書いてもらったものを貼り付けています。
実装は人間が行なっています。

Day 12: Christmas Tree Farm

part1 問題概要

入力が以下のように与えられます。
入力で与えられた$n * m$の長方形にid: iの3 * 3の正方形をn個というのをすべて重ならずに置けるかどうかを判定してという問題です。
図形は回転OKです。

0:
###
##.
##.

1:
###
##.
.##

2:
.##
###
##.

3:
##.
###
##.

4:
###
#..
###

5:
###
.#.
###

4x4: 0 0 0 0 2 0
12x5: 1 0 1 0 2 2
12x5: 1 0 1 0 3 2

解答

みんな大好きpolynomioが頭をよぎりました。

ただ、本番入力を見てみると値がデカすぎます。
いくらなんでも全探索できません。

38x47: 30 28 36 34 25 27
47x38: 42 45 49 50 43 45
41x40: 53 37 45 43 39 34
43x43: 44 51 43 48 50 50
36x36: 10 17 29 26 31 30
40x36: 35 37 41 46 38 25

全探索以外に妥当な方法が見つからず、さすがに困ってしまってしまいました...

本当に方法がわからないので、探索が必要なものを炙り出すことにしました。

逆に探索が必要ないものは以下の2通りが考えられました。

  • 3 * 3を重ねずに置いていってもおけるくらいh * wが大きければ必ずおける。
  • #の数を数えて、その数がh * wより大きければどう頑張っても置けない

すると、すべて↑のケースで弾かれることがわかりました。
つまりは入力で与えられるケースは適当においても余裕があるケースか、どう頑張ってもおけないケースしか与えられてきませんでした。

よって本当は解けていませんが、この入力では解くことができました。
これ本当に現実的な時間で弱いケース以外も判定する方法あるんですかね...

use itertools::Itertools;
use proconio::{input, marker::Chars};

fn main() {
    let mut blocks = vec![];
    let count = 6;
    let case = 1000;
    let mut bs = vec![];
    for _ in 0..count {
        input! {
            _n: String,
            s: [Chars; 3]
        }
        bs.push(s.iter().flatten().filter(|&&e| e == '#').count());
        blocks.push(s);
    }

    let mut ans = 0usize;
    for _ in 0..case {
        input! {
            mut s: String,
            count: [usize; 6]
        }
        s.pop();
        let s = s.split('x').collect_vec();
        let h = s[0].parse::<usize>().unwrap();
        let w = s[1].parse::<usize>().unwrap();
        let cs = count.iter().sum::<usize>();

        let mut c = 0;
        for i in 0..6 {
            c += count[i] * bs[i];
        }

        if h / 3 * w / 3 >= cs {
            ans += 1usize;
        } else if c > h * w {
            continue;
        } else {
            // ここを通るケースがないのでこれでこの問題はとけます...
            panic!("ここを通ると他の解法が必要です...!!")
        }
    }
    println!("{}", ans);
}

atcoderでは絶対に出題されないようなコーナーケース的な問題で面白かったです

part2

省略します。part1を解いてお読みください。

終わりに

image.png

無事すべての問題を解けてピカピカになりました!!
楽しかったです。来年もやりたいです!

1
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
1
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?