AtCoder

ABC374 D問題(Laser Marking)を解く

AtCoder_ABC374_D

AtCoder が提供しているABC(AtCoder Beginner Contest)374 D問題をC++で解いてみました。ABC374は、2024年10月5日21:00に実施されました。

AtCoder の紹介はこちらに、プログラミングの方針はこちらに記事があります。

D問題 Laser Marking(Difficulty : 694)

問題の詳細は、リンク先をご覧ください。

ABC374 D問題 Laser Marking

再帰関数で全検索しました。AtCoder Problems による Difficulty は 694 でした。

解答案

$1 \leqq N \leqq 6$ と制約が小さいため、線分を選ぶすべての順列($6!$)に対して、端を選ぶ $2^6$ 通りを掛けても $6! \times 2^6 = 46080$ 通りであるため、全検索しても十分に間に合います。

C++ プログラム例(ABC374D)

再帰関数で実装しました。

  • 再帰関数 rec の引数は、いま選んでいる線分 i、方向 direction、今までの時間の累計 dist です。
  • 最初に線分を選び、両端に対して再起関数 rec を呼びます(65、66行目)。
  • 再帰関数 rec で以下を計算します。
    • 選択した線分の長さを照射する時間を求めます(14-15行目)。
    • もしすべての線分が選択されていたら、その時間の累計が最小値となっているか確認します(16ー22行目)。
    • まだ選択されていない線分があれば、その線分を選び、両端に対して再起関数 rec を呼びます(33ー51行目)。

以下が、C++プログラムです。一部の長い行は折り返しています。

#include <bits/stdc++.h>
using namespace std;

#define INF (double)(1LL << 60)

int n;
double s, t;
vector<int> a(6), b(6), c(6), d(6);
vector<bool> used(6, false);
double result = INF;

void rec(int i, int direction, double dist)
{
	dist +=
		sqrt((a[i] - c[i]) * (a[i] - c[i]) + (b[i] - d[i]) * (b[i] - d[i])) / t;
	bool is_full = true;
	for (int j = 0; j < n; ++j) {
		if (!used[j]) {
			is_full = false;
			break;
		}
	}
	if (is_full) {
		result = min(result, dist);
		return;
	}

	for (int j = 0; j < n; ++j) {
		if (used[j]) {
			continue;
		}
		used[j] = true;
		if (direction == 0) {
			rec(j, 0,
				dist + sqrt((c[i] - a[j]) * (c[i] - a[j]) +
							(d[i] - b[j]) * (d[i] - b[j])) /
						   s);
			rec(j, 1,
				dist + sqrt((c[i] - c[j]) * (c[i] - c[j]) +
							(d[i] - d[j]) * (d[i] - d[j])) /
						   s);
		} else {
			rec(j, 0,
				dist + sqrt((a[i] - a[j]) * (a[i] - a[j]) +
							(b[i] - b[j]) * (b[i] - b[j])) /
						   s);
			rec(j, 1,
				dist + sqrt((a[i] - c[j]) * (a[i] - c[j]) +
							(b[i] - d[j]) * (b[i] - d[j])) /
						   s);
		}
		used[j] = false;
	}
}

int main()
{
	cin >> n >> s >> t;
	for (int i = 0; i < n; ++i) {
		cin >> a[i] >> b[i] >> c[i] >> d[i];
	}

	for (int i = 0; i < n; ++i) {
		used[i] = true;
		rec(i, 0, sqrt(a[i] * a[i] + b[i] * b[i]) / s);
		rec(i, 1, sqrt(c[i] * c[i] + d[i] * d[i]) / s);
		used[i] = false;
	}

	cout << fixed << setprecision(12);
	cout << result << endl;

	return 0;
}

AC(Accepted=正しいプログラム)と判定されました。

今回は、Python プログラムの紹介は見送ります。

最後に

再帰関数にも慣れてきました。

引き続き ABC の問題を紹介していきます。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA