Word Composition

From a given list of strings, determine whether it can compose a target word with each word only allowed to extract at most one character.

example:

["abc", "bcd"] , target = "bb" => yes

["abc", "def"] , target = "ba" => no

Thoughts:

Think it as an bipartite matching problem to find the maximal matching number: if it equals the length of the target string, return true, else return false;

Code

// cin with strings
#include <iostream>
#include <string>
#include <vector>
#include <cstring>

using namespace std;

/**
 *From a given list of strings, determine whether it can compose a target word with
 * each word only allowed to extract at most one character.
 * example:
 * ["abc", "bcd"] , target = "bb" => yes
 * ["abc", "def"] , target = "ba" => no
 */
class WC {
    struct Edge {
        int from;
        int to;
        int weight;

        Edge(int f, int t, int w) : from(f), to(t), weight(w) {};
    };

    typedef vector<int>::iterator iterator_t;
    vector<string> words;
    string target;
    int _maxNodes;
    int num_left;
    vector<int> matching ;
    vector<int> check;
    vector<vector<int>> G;
    vector<Edge> edges;
public:
    WC(vector<string> w, string t) {
        words = w;
        num_left = static_cast<int>(w.size());
        cout<<num_left<< " " << t.size()<< endl;
        _maxNodes = static_cast<int>(w.size() + t.size());
        cout<<_maxNodes<< " _maxNodes" << endl;
        // assign some values:
        G.resize(_maxNodes);
        matching.resize(_maxNodes);
        check.resize(_maxNodes);
        fill(matching.begin(),matching.end(),-1);
        fill(check.begin(),check.end(),-1);
//        for (unsigned i=0; i<_maxNodes; i++) {matching[i]=-1; check[i]=0;}

        target = t;
        for(int i = 0; i < num_left; i++){
            for(int j = 0; j < t.size(); j++){
                if(words[i].find(t[j])!=string::npos) {
                    G[i].push_back(num_left+j); G[num_left+j].push_back(i);
                    edges.emplace_back(i, num_left+j, 0);
                    edges.emplace_back(num_left+j, i,0);
                }
            }
        }
        cout<<G.size()<<endl;
        cout<<" last vec in G: ";
        for(auto num: G[1]) cout<<num<<" ";
        cout<<endl;
        cout<<edges.size()<<endl;
    }

    int wordComposition(vector<string> words, string targets) {
        /* for(auto w: words) cout<<w<<" "<<endl;
         cout<<targets<<endl;
       */
       return hungarian();
    }

    bool dfs(int u) {
        for (iterator_t i = G[u].begin(); i != G[u].end(); ++i) { // 对 u 的每个邻接点
            int v = *i;//edges[*i].to;
            if (!check[v]) {     // 要求不在交替路中
                check[v] = true; // 放入交替路
                if (matching[v] == -1 || dfs(matching[v])) {
                    // 如果是未盖点,说明交替路为增广路,则交换路径,并返回成功
                    matching[v] = u;
                    matching[u] = v;
                    return true;
                }
            }
        }
        return false; // 不存在增广路,返回失败
    }

    int hungarian(){
        int ans = 0;
//      memset(matching, -1, sizeof(matching));
        fill(matching.begin(), matching.end(), -1);
        for (int u=0; u < num_left; ++u) {
            if (matching[u] == -1) {
//              memset(check, 0, sizeof(check));
                fill(check.begin(), check.end(), 0);
                if (dfs(u)){
                    cout <<"matched val: "<<u<<endl;
                    ++ans;
                }
            }
        }
        return ans;
    }
};

int main() {
    vector<string> words = {"cb","6","3", "last?","one", "with", "y", "i", "sa", "t","nn","re?", "hello"};
    string target = "c6?onewith";
    WC wc(words, target);
    int matchedNum = wc.wordComposition(words, target);
    cout<< "matchedNum: " <<matchedNum <<endl;
    bool ans = (target.size() == matchedNum );
    cout.setf(ios_base:: boolalpha);
    cout<< ans <<endl;

    return 0;
}

Last updated

Was this helpful?