AtCoder

ABC310 D問題(Peaceful Teams)を解く

AtCoder_ABC310_D

AtCoder が提供しているABC(AtCoder Beginner Contest)310 のD問題をC++とPythonで解いてみました。ABC310は、2023年7月15日21:00に実施されました。

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

D問題 Peaceful Teams(Difficulty : 1368)

問題はリンク先をご覧ください。

ABC310 D問題 Peaceful Teams

DFSを用いて全探索する問題です。AtCoder Problems による Difficulty は 1368 でした。

解答案

再帰を使って全探索を行います。変数 team は、配列の配列(リストのリスト)とします。team[j] は、j 番目のチームを表す配列(リスト)となります。

再帰関数 dfs の処理は以下となります。引数 i は、i 番目のメンバを処理することを表します。

  • 引数 i が n となった場合、すべての人がチームに所属した。以下の処理を行う。
    • チームの数が t であれば、条件を満たすため result を増やす。
    • 関数から戻る。
  • 存在するチームに相性の悪い相手がいなければ、そのチームに i を加えて、次の i+1 を引数に dfs を呼び出す。dfs から戻った後は、チームから i の値を抜いて、無かったことにして、次のチームに対して処理を行う。
  • 新しいチームに i を加えて、次の i+1 を引数に dfs を呼び出す。dfs から戻った後は、そのチームを無かったことにする。

チームメンバーを増やして、dfs 呼び出し後にそのチームメンバーを無かったことにして、次を調べることをバックトラックと呼ぶようです。

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

上記の考察に従い、関数 dfs を実装します。

main では入力を読み、相性の悪い相手を表す配列 ng を更新して、dfs を呼び出します。このプログラムのキーとなる行の背景色を変更しておきます。

以下が、C++プログラムとなります。

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

int n;
int t;
int m;
vector<vector<bool>> ng(10, vector<bool>(10, false));
vector<vector<int>> team;
int result;

void dfs(int i)
{
	if (i == n) {
		if (team.size() == t) {
			++result;
		}
		return;
	}

	for (int j = 0; j < team.size(); ++j) {
		bool this_team = true;
		for (auto e : team[j]) {
			if (ng[e][i]) {
				this_team = false;
			}
		}
		if (this_team) {
			team[j].push_back(i);
			dfs(i + 1);
			team[j].pop_back();
		}
	}

	team.push_back(vector<int>(1, i));
	dfs(i + 1);
	team.pop_back();

	return;
}

int main()
{
	cin >> n >> t >> m;
	for (int i = 0; i < m; ++i) {
		int a, b;
		cin >> a >> b;
		--a;
		--b;
		ng[a][b] = true;
		ng[b][a] = true;
	}

	result = 0;
	dfs(0);

	cout << result << endl;

	return 0;
}

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

Python プログラム例(ABC310D)

C++ 版をそのまま移植しました。Python の多くの環境は、再帰関数の呼び出し回数の制限が 1000 回であるため、それを増やしています(5行目)。

"""AtCoder Beginner Contest 310 D"""
import sys

LIMIT = 10**6
sys.setrecursionlimit(LIMIT + 1)


def dfs(i):
    global n
    global t
    global ng
    global team
    global result

    if i == n:
        if len(team) == t:
            result += 1
        return

    for j in range(len(team)):
        this_team = True
        for e in team[j]:
            if ng[e][i]:
                this_team = False
        if this_team:
            team[j].append(i)
            dfs(i + 1)
            team[j].pop(-1)

    team.append([i])
    dfs(i + 1)
    team.pop(-1)

    return


n, t, m = map(int, input().split())
ng = [[False for i in range(n)] for j in range(n)]
for i in range(m):
    a, b = map(int, input().split())
    a -= 1
    b -= 1
    ng[a][b] = True
    ng[b][a] = True

team = []
result = 0
dfs(0)

print(result)

こちらも「AC」と判定されました。

最後に

この問題は、コンテスト中に解くことができませんでした。公式解説を参考にして解いてみました。自分でプログラムをすることにより、DFS を使った全探索について、理解を深めることができました。

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

COMMENT

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

CAPTCHA