AtCoder

ABC344 D問題(String Bags)を解く

AtCoder_ABC344_D

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

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

D問題 String Bags(Difficulty : 854)

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

ABC344 D問題 String Bags

DPで解くことができます。AtCoder Problems による Difficulty は 854 でした。

解答案

DPで解くことができます。dp[i][j] を袋を i 個を処理した後に 文字列 T の j 文字目まで一致している最小の支払い金額とします。

出力する回答は、dp[N][Tの長さ] となります。

漸化式は、以下となります。

  • なにもしない場合:
     i を小さい方から処理して、すべての j に対して
     dp[i+1][j] = dp[i][j]
  • 袋 i から、文字を取り出して T の j 文字目の直前と一致している場合:
     dp[i+1][j] = dp[i][j – 取り出した文字列の長さ] + 1
     ただし、最小値となる場合のみ更新する。

初期値は、以下となります。

  • dp[0][0] = 0
  • それ以外の場合は、無限大(十分に大きな値とする)

問題の見た目は異なりますが、ナップザック問題と同じ構造になっています(部分文字列が一致している条件がありますが)。

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

上で解説した漸化式を実装しました。以下が、C++プログラムとなります。

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

#define INF (1 << 30)

int main()
{
	string t;
	cin >> t;
	int n;
	cin >> n;
	vector<vector<string>> a(n);
	for (int i = 0; i < n; ++i) {
		int size;
		cin >> size;
		for (int j = 0; j < size; ++j) {
			string temp;
			cin >> temp;
			a[i].push_back(temp);
		}
	}

	int ts = t.length();
	vector<vector<int>> dp(n + 1, vector<int>(ts + 1, INF));
	dp[0][0] = 0;
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j <= ts; ++j) {
			dp[i + 1][j] = dp[i][j];
			for (int k = 0; k < a[i].size(); ++k) {
				int len = a[i][k].length();
				if ((j - len >= 0)&&(t.substr(j - len, len) == a[i][k])) {
					dp[i + 1][j] = min(dp[i + 1][j], dp[i][j - len] + 1);
				}
			}
		}
	}

	if (dp[n][ts] == INF) {
		cout << -1 << endl;
	} else {
		cout << dp[n][ts] << endl;
	}

	return 0;
}

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

Python プログラム例(ABC344D)

Python 版も基本的な考え方は同じです。以下となります。

"""AtCoder Beginner Contest 344 D"""
INF = 1 << 30
t = input()
n = int(input())
a = [[] for _ in range(n)]
for i in range(n):
    a[i] = list(input().split())
    del a[i][0]

ts = len(t)
dp = [[INF for _ in range(ts + 1)] for _ in range(n + 1)]
dp[0][0] = 0
for i in range(n):
    for j in range(ts + 1):
        dp[i + 1][j] = dp[i][j]
        for k in range(len(a[i])):
            len_s = len(a[i][k])
            if j - len_s >= 0 and t[j - len_s:j] == a[i][k]:
                dp[i + 1][j] = min(dp[i + 1][j], dp[i][j - len_s] + 1)

print(-1 if dp[n][ts] == INF else dp[n][ts])

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

最後に

この問題は、In-Placeに書いて1次元で計算したらWA判定されました。コンテスト中には、ACを取ることができませんでした。素直に2次元で書けばよかったと思います。

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

COMMENT

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

CAPTCHA