TopCoder SRM 330 Div1 Medium PrefixFreeSubsets
問題
文字列の集合がprefix-freeであるとは、
どの文字列も、他の文字列の接頭辞となっていないことをいう。
空の文字列もprefix-freeである。
文字列の集合が与えられる。
この集合の部分集合(空集合および、元の集合そのものも含む)のうち、prefix-freeであるものはいくつあるか、求めよ。
制約条件
集合の要素≦50
各文字列の長さ≦50
集合の要素は全て互いに異なる
方針
文字列jが、文字列iの接頭辞であるとき、i→jに辺を張ったグラフを考える。
ただし、別の文字列kがあって、i→k→jと接頭辞になっているときはi→jには辺を張らない。
このグラフは森になる。
このグラフ上の、安定集合が求める集合である。
これは木のDPをすればいい。
木のDPは、根を使う場合が1通りと、
根を使わない場合が、それぞれの子の場合の数を掛け合わせたものになるので、メモ化再帰をすればいい。
ソースコード
bool prefix(string a,string b){ return a.size()<b.size()&&a==b.substr(0,a.size()); } int n,deg[50]; bool pre[50][50]; ll dp[50]; ll rec(int c){ if(dp[c]>=0)return dp[c]; dp[c]=1; rep(i,n)if(pre[c][i])dp[c]*=rec(i); dp[c]+=1; return dp[c]; } class PrefixFreeSubsets { public: long long cantPrefFreeSubsets(vector <string> words) { memset(pre,0,sizeof(pre)); memset(deg,0,sizeof(deg)); memset(dp,-1,sizeof(dp)); n=words.size(); rep(i,n)rep(j,n)if(prefix(words[i],words[j])){ rep(k,n)if(prefix(words[i],words[k])&&prefix(words[k],words[j]))goto FAIL; pre[i][j]=1; deg[j]++; FAIL:; } ll ans=1; rep(i,n)if(deg[i]==0)ans*=rec(i); return ans; }