【问题标题】:Rearrange word order so that first and last letters match重新排列单词顺序,使第一个和最后一个字母匹配
【发布时间】:2022-12-10 16:41:31
【问题描述】:

如何编写 C++ 代码来重新排列词序,使每个单词的第一个字母(第一个除外)等于前一个单词的最后一个字母?

细节:

输入单词列表,每行一个单词,所有字母小写 a 到 z

输出一个有序的单词列表,每个单词的第一个字母(第一个除外)等于前一个单词的最后一个字母。必须使用列表中的所有单词,每个单词恰好出现一次。多次提到的词必须使用该次数。

【问题讨论】:

    标签: c++ graph-theory


    【解决方案1】:

    这是进行匹配的代码

    #include <string>
    #include <fstream>
    #include <sstream>
    #include <iostream>
    #include <vector>
    #include <set>
    #include <algorithm>
    
    class cGraph;
    
    /// @brief Spanning tree
    class cTree
    {
        cGraph &myGraph;
    
        /// @brief  links in spanning tree
        std::vector<std::pair<int, int>> myLink;
    
        std::vector<bool> myVisited;
    
        /// @brief links arranged so last matched next first
        std::vector<std::pair<int, int>> myArrange;
    
    public:
        cTree(cGraph &g)
            : myGraph(g)
        {
        }
    
        void add(int n1, int n2)
        {
            myLink.push_back(std::make_pair(n1, n2));
        }
        int nodeCount();
    
        std::string text();
    
        /// @brief Depth first search starting at a link
        /// @param link
        /// @return true if every word was reached
        bool dfs(
            const std::pair<int, int> &link);
    
        /// @brief arrange words into required order
        ///
        /// The last letter of each word must be the
        /// same as the first letter of the next word
        std::vector<std::pair<int, int>> arrange();
    };
    
    class cGraph
    {
        std::vector<std::string> myWord;
        std::vector<std::vector<bool>> myAdj;
        std::vector<std::pair<int, int>> myArrange;
    
    public:
        void setSize(int s)
        {
            myAdj.resize(s, std::vector<bool>(s, false));
        }
        void addLink(int n1, int n2)
        {
            myAdj[n1][n2] = true;
        }
    
        void read(const std::string &fname);
    
        void constructAdjacencyMatrix();
    
        int wordCount() const
        {
            return myWord.size();
        }
        std::string word(int idx) const
        {
            return myWord[idx];
        }
    
        std::vector<int> sources(int n);
        std::vector<int> targets(int n);
    
        void arrange();
    
        void displayArrange();
    
    private:
        cTree spanningTree();
    };
    
    int cTree::nodeCount()
    {
        std::set<int> nodes;
        for (auto &l : myLink)
        {
            nodes.insert(l.first);
            nodes.insert(l.second);
        }
        return nodes.size();
    }
    
    std::string cTree::text()
    {
        std::stringstream ss;
        for (auto &l : myLink)
            ss << myGraph.word(l.first)
               << " -> "
               << myGraph.word(l.second)
               << " ";
        return ss.str();
    }
    
    std::vector<int> cGraph::sources(int n)
    {
        std::vector<int> ret;
        int n1idx = -1;
        for (auto &vl : myAdj)
        {
            n1idx++;
            int n2idx = -1;
            for (bool l : vl)
            {
                n2idx++;
                if (n2idx == n)
                    if (l)
                        ret.push_back(n1idx);
            }
        }
        return ret;
    }
    std::vector<int> cGraph::targets(int n)
    {
        std::vector<int> ret;
        int n2idx = -1;
        for (bool l : myAdj[n])
        {
            n2idx++;
            if (l)
                ret.push_back(n2idx);
        }
    
        return ret;
    }
    
    cTree cGraph::spanningTree()
    {
        cTree mySpanningTree(*this);
        std::vector<bool> visited(myAdj.size(), false);
    
        // add initial arbitrary link
        int v, w;
        for (v = 0; v < myAdj.size(); v++)
        {
            auto vt = targets(v);
            if (vt.size())
            {
                w = vt[0];
                mySpanningTree.add(v, w);
                break;
            }
        }
        if (v == myAdj.size())
            throw std::runtime_error("no links");
    
        visited[v] = true;
        visited[w] = true;
    
        // while nodes remain outside of span
        bool fdone = false;
        while (!fdone)
        {
            // loop over nodes in span
            for (v = 0; v < myAdj.size(); v++)
            {
                if (!visited[v])
                    continue;
    
                // loop over nodes not in span
                fdone = true;
                for (w = 0; w < myAdj.size(); w++)
                {
                    if (visited[w])
                        continue;
    
                    fdone = false;
    
                    if (myAdj[v][w])
                    {
                        mySpanningTree.add(v, w);
                        visited[w] = true;
                    }
                    if (myAdj[w][v])
                    {
                        mySpanningTree.add(w, v);
                        visited[w] = true;
                    }
                }
            }
            if (v == myAdj.size())
                fdone = true;
        }
    
        if (mySpanningTree.nodeCount() < myAdj.size())
            throw std::runtime_error(
                "Spanning tree incomplete: no solution available
    ");
    
        // std::cout << "
    "
        //           << mySpanningTree.text() << "
    ";
    
        return mySpanningTree;
    }
    
    void cGraph::arrange()
    {
        // Find a spanning tree and search it for a matching word arrangement
        // throw exception if no arrangement possible
        myArrange = spanningTree().arrange();
    }
    
    void cGraph::displayArrange()
    {
        // display the arrangement found
        std::cout << "arrange into "
                  << word(myArrange[0].first) << " ";
        for (auto &l : myArrange)
            std::cout << word(l.second) << " ";
        std::cout << "
    ";
    }
    
    void cGraph::read(const std::string &fname)
    {
        std::ifstream ifs(fname);
        if (!ifs.is_open())
        {
            std::cout << "cannot open input
    ";
            exit(1);
        }
        std::string word;
        ifs >> word; // skip count
        while (ifs.good())
        {
            ifs >> word;
            myWord.push_back(word);
            std::cout << word << "
    ";
        }
        setSize(myWord.size());
    }
    
    void cGraph::constructAdjacencyMatrix()
    {
        int widx = -1;
        for (auto &w : myWord)
        {
            widx++;
            char first = w[0];
            char last = w[w.length() - 1];
            int sidx = -1;
            for (auto &src : myWord)
            {
                sidx++;
                if (sidx == widx)
                    continue;
                if (src[src.length() - 1] == first)
                {
                    addLink(sidx, widx);
                }
                if (src[0] == last)
                {
                    addLink(widx, sidx);
                }
            }
        }
    }
    
    bool cTree::dfs(
        const std::pair<int, int> &l)
    {
        myVisited[l.first] = true;
        myVisited[l.second] = true;
        bool fdone = true;
        for (bool v : myVisited)
        {
            if (!v)
            {
                fdone = false;
                break;
            }
        }
        if (fdone)
        {
            myArrange.push_back(l);
            return true;
        }
    
        auto visited_save = myVisited;
        for (const auto &lnext : myLink)
        {
            if (lnext.first == l.second)
            {
                myVisited = visited_save;
                if (dfs(lnext))
                {
                    myArrange.push_back(l);
                    return true;
                }
            }
        }
        return false;
    }
    
    std::vector<std::pair<int, int>> cTree::arrange()
    {
        // loop over links in spanning tree
        for (const auto &l : myLink)
        {
            // do a depth fist search through the tree
            // starting from this link
            myVisited.clear();
            myVisited.resize(myGraph.wordCount(), false);
            if (dfs(l))
            {
                // the dfs reached every word
                // reverse the order in which the words were found
                // which gives an arrangement of words in required order
                std::reverse(myArrange.begin(), myArrange.end());
    
                // done
                return myArrange;
            }
        }
    }
    
    main()
    {
        cGraph graph;
    
        // read word list from file
        graph.read("input.txt");
    
        // connect matching words
        graph.constructAdjacencyMatrix();
    
        // arrange words, matching first and last letters
        graph.arrange();
    
        // output results
        graph.displayArrange();
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-13
      • 2016-11-25
      • 2012-02-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多