この問題はbit全探索を問います。
文字列を選ぶのは 通りあります。これは よりbit全探索で探索することが可能です。
さらにそのうちの文字を選び取って組み合わせる操作は「適当に組み合わせる」操作なので、どのような順番で文字を選び取っても構いません。
これは文字を組み合わせた結果が選び取った各文字の個数のみに依存することを表します。
よって に含まれる各文字の個数 ※ を数え、 から選び取った各文字を個数 として数え、すべての に対し を満たすかどうか調べればよいです。どのような場合だとしても、そのような が存在しないなら答えは -1
です。
以上から で解くことが可能です( は文字列 の長さを表します)。以下、解答例(C++,Python)です。
※ 英小文字は 種類あるためです。また a
はASCIIコード に相当するので、各文字のASCIIコード とすると が成り立ちます。しかしこれは 0-indexed の時であり、上の場合では 1-indexed なので が成り立ちます。
xxxxxxxxxx
//[0,n)
//[a,b)
using namespace std;
using ll = long long;
using ull = unsigned long long;
using P = pair<ll,ll>;
using pq = priority_queue<P,vector<P>,greater<P>>;
const ll inf = 8e18;
const int iinf = (int)1e9;
const int mod9 = 998244353;
const int mod1 = 1000000007;
struct Edge { int to; ll cost; int from; };
bool compe(const Edge &e,const Edge &e2){ return e.cost < e2.cost; }
using Graph = vector<vector<int>>;
using SGraph = vector<set<ll>>;
template <typename T>
int siz(T& a){return (int)a.size();}
int main(void){
string s; cin >> s;
int n; cin >> n;
vector<string> T(n); rep(i,n) cin >> T[i];
vector<int> as(26,0);
rep(i,siz(s)) as[s[i]-'a']++;
int ans = iinf;
for(int b = 1; b < (1<<n); b++){
vector<int> at(26,0);
int now = 0;
rep(i,n){
if(b & (1<<i)){
rep(j,siz(T[i])) at[T[i][j]-'a']++;
now++;
}
}
bool ok = 1;
rep(i,26) if(as[i] > at[i]) ok = 0;
if(ok) ans = min(ans,now);
}
cout << (ans == iinf ? -1 : ans);
}
xxxxxxxxxx
from itertools import product
S = input()
N = int(input())
T = list(input().split())
alpS = [0 for i in range(26)]
for s in S:
alpS[ord(s)-97] += 1
ans = N+1
for p in product((0,1),repeat = N):
alpT = [0 for i in range(26)]
now = 0
for i in range(N):
if p[i] == 1:
for c in T[i]:
alpT[ord(c)-97] += 1
now += 1
ok = True
for i in range(26):
if alpT[i] < alpS[i]:
ok = False
if ok == True:
ans = min(ans,now)
print(-1 if ans == N+1 else ans)