【问题标题】:Words of length k generation from a DFA来自 DFA 的长度为 k 代的词
【发布时间】:2016-07-14 18:50:26
【问题描述】:

美好的一天, 我在生成一个包含所有长度为 k 的单词的列表时遇到了一个严重的问题(生成函数是旨在生成所有长度为 k 的单词的函数,另一个函数用于确定一个单词是否被接受) 仅通过使用 DFS 算法从 DFA 中获取,这是我的尝试:

#include<vector>
#include<iostream>
#include<fstream>
#include<string.h>

using namespace std;

vector < pair <int,char> > a[100];

int viz[100], v[100];
char s1[100];

void accepted (int q, char c, char s[100], int x) {
    c = s[x];
    viz[q] = 1;
    cout << q;
    for (int i = 0; i < a[q].size(); i++)
        if (a[q][i].second == c) {
            x++;
            accepted (a[q][i].first, a[q][i+1].second, s, x);
        }
}

void generate (int q, int k) {
    int x = 0;
    v[q] = 1;
    while (x < k) {
        cout << a[q][0].second;
        for (int i = 0; i < a[q].size(); i++)
            if (v[a[q][i].first] == 0)
            {
                cout << a[q][i].second;
                generate(a[q][i].first, k);
            }
        x++;
    }
}

int main() {
    ifstream f ("input.txt");
    int n, m, x, y, i, j, k;
    char c;
    char s[100];
    f >> n >> m;
    for (i = 0; i < m; i++) {
            f >> x >> y;
            f >> c;
            a[x].push_back (make_pair(y,c));
            }
    for (i = 0; i < n; i++) {
        cout << i << ": ";
        for (j = 0; j < a[i].size(); j++)
            cout << a[i][j].first << a[i][j].second << " ";
        cout << endl;
    }
    cout << endl << "Fiite states: 2, 3" << endl << endl;
    cin.get (s,100);
    accepted(0, s[0], s, 0);
    if (viz[2] == 1) cout << endl << "Accepted";
    cout << endl;
    cin >> k;
    generate (0, k);
    cout << endl;
    return 0;
}

这也是我的输入的样子:

4 6
0 0 a
0 1 b
1 2 c
2 2 a
2 3 c
3 3 c

DFA 和输出如下所示:

我面临的严重问题是我无法通过调用 generate 函数将所有获得的单词正确地输出到屏幕上。

【问题讨论】:

  • 你不是已经问过这个问题了吗?
  • 我做了,但一开始还不够详细

标签: c++ algorithm c++11 c++14 dfa


【解决方案1】:

我更改了您的生成功能,如下所示。接下来是关于我的想法以及我如何改变它的解释。

void generate (int q, int k, string &s) {
    if (k > 0) {
        for (int i = 0; i < a[q].size(); i++)
        {
            s += a[q][i].second;
            generate(a[q][i].first, k-1, s);
            s.pop_back();
        }
    }
    else {
        cout << s << endl;
    }
}

首先,您尝试混合使用 DFS 的递归和重复版本,但如果您是使用显式堆栈的重复版本,那么您没有保留堆栈的结构,而且我怀疑。基本上,您的外部 while 循环是错误的,因为 深度应该随着您递归遍历图表而增加,而不是像您那样使用 while 循环在单个递归级别重复。正如我所提到的,您还可以采用一种重复的方法并使用显式定义的堆栈,而不是在递归实现 DFS 时由内存隐式使用的堆栈。但是通过递归实现更容易和更直观地掌握 DFS,因此我省略了外部循环。

其次,保留已访问节点的列表不是一个好主意,因为您想列出 所有 k 长度的字符串,并且 您的 DFA 不是一个简单的图表。 (即从节点 u 到节点 u 可能存在边)所以我删除了 for 循环内的 if 语句,因为您可以多次访问理智的节点。您的方法是基于 DFA 的分支因子的指数方法,但是如果您的 k 足够小,则无论如何它都应该起作用。指数方法不是您正在寻找的解决方案的问题。

第三,可能是由于您使用了 while 循环,因此在每个级别都打印了一个字符,这是不正确的。请记住,在深度为 k 的每个节点,您必须从树的根部开始打印所有您遇到的字符。这就是为什么我在你的函数中添加了一个字符串作为第三个参数。不过不用担心,它是通过引用传递的,它只会给您的算法增加 O(k) 空间复杂度,这应该可以忽略不计。

如果在你的 main 函数中使用下面的调用开始遍历,你会发现它工作正常。

string S;
generate(0, k, S);

【讨论】:

  • 它给了我以下错误:std::string has no member named 'pop_back'
  • pop_back 从 c++11 开始定义。既然你的问题有那个标签,我认为它会起作用。
  • 你可以使用擦除来代替:s.erase(s.size()-1, 1);
  • 我已经用c++11搞定了,我现在试试,谢谢
  • 感谢@ilim 的修复和详细解释,它就像一个魅力
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-17
  • 1970-01-01
  • 1970-01-01
  • 2017-04-06
  • 2017-03-05
  • 1970-01-01
相关资源
最近更新 更多