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 3: Lobby をRustで解いた

Last updated at Posted at 2025-12-04

Advent of Code

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

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

Day 3: Lobby

part1 問題概要

  • 入力は複数行の数字列(例:987654321111111 など)。
  • 各行は「バッテリーバンク」を表していて、1桁1桁が 電池の「電圧 (1〜9)」
  • 各バンクでは、ちょうど2つの電池を選んで ON にする。
  • 桁の順番は並べ替えできない。
  • 例えば 12345 で 2番目と4番目の電池をつけると、24 ジョルト。
  • 各バンクについて、その行の中から2つ位置を選ぶ
  • その2つの桁で作れる2桁の数のうち 最大のもの を求める

最後に:
すべてのバンクについて求めた「最大ジョルテージ」を全部足した合計
→ これが答え。

解答

入力が200行しかなく、各行も100桁くらいの数で飛んでくるので $\binom{100}{2} = 4950$ なので4950 * 200なので全探索しても余裕です。
ただ、選べるものを貪欲に取った方が計算量的に優しいと思ったので、mapを使って貪欲に取りました。
ここで言う「選べるもの」とは10の位としてとった数より右になる数字全部をさします。

fn main() {
    let n = 200;
    input! {
        s: [Chars; n]
    }
    let nums = s
        .iter()
        .map(|e| {
            e.iter()
                .map(|e| e.to_string().parse::<usize>().unwrap())
                .collect_vec()
        })
        .collect_vec();
    let mut ans = 0;
    for row in nums.iter() {
        let mut map = BTreeMap::new();
        for &num in row.iter() {
            map.entry(num).and_modify(|e| *e += 1).or_insert(1usize);
        }
        let mut t = 0;
        for &num in row.iter() {
            let &pre = map.get(&num).unwrap();
            if pre == 1 {
                map.remove(&num);
            } else {
                map.insert(num, pre - 1);
            }
            let la = map.last_key_value();
            if la.is_none() {
                continue;
            }
            let &la = la.unwrap().0;
            let now = num * 10 + la;
            t = max(t, now);
        }
        ans += t;
    }
    println!("{}", ans);
}

part2 問題概要

part1では2桁で最大のものを選んでいましたが、part2では12桁になります。

解答

$\binom{100}{12} = 1.0504210511E15$ なのでいくらなんでも全探索ができません。

  • 大きい数字からとっていきたい
  • 後で選べる余地を大きくしたいので、なるべく左の数字をとりたい

ということはわかるので、選べる数字を貪欲に取る解放で解けます。
ここで言う「選べるもの」とは、その桁をとっても12桁埋められる数字全体です。

例えば、12桁の一番大きい位を埋めようとして、おしり11個の中から選んでとってしまうと12桁埋められなくなってしまうので、こういう値はのぞいて貪欲に数字を埋めていきます

fn main() {
    let n = 200;
    let choose = 12;
    input! {
        s: [Chars; n]
    }
    let nums = s
        .iter()
        .map(|e| {
            e.iter()
                .map(|e| e.to_string().parse::<usize>().unwrap())
                .collect_vec()
        })
        .collect_vec();
    let mut ans = 0;
    for row in nums.iter() {
        let mut set = BTreeSet::new();
        let fe = row.len() - choose;
        for i in 0..=fe {
            set.insert((Reverse(row[i]), i));
        }
        let mut now = 0;
        let mut a: Vec<usize> = vec![];
        while a.len() < choose {
            let fi = set.pop_first().unwrap();
            if fi.1 < now {
                continue;
            }
            now = fi.1;
            let fi = fi.0.0;
            a.push(fi);
            if fe + a.len() < row.len() {
                set.insert((Reverse(row[fe + a.len()]), fe + a.len()));
            }
        }
        assert_eq!(a.len(), choose);
        let num = a.iter().join("").parse::<usize>().unwrap();
        ans += num;
    }
    println!("{}", ans);
}

終わりに

day4も頑張ります!

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?