算法小结:有向无环图对于哈密顿路径的多项式时间算法

问题

在有向无环图DAG(Directed acyclic graph)中,哈密顿路径问题(Hamiltonian-path)可以在多项式时间内解决。请给出具体算法。

算法思路

算法:

  1. 对有向无环图进行拓扑排序(topological sort)

  2. 验证排序结果

    • 如果对于任意点u,以及排序结果中其下一个结点v,存在(u,v),则哈密顿路径存在,并且就是拓扑排序返回结果

    • 如果对于某个点u,以及排序结果中其下一个结点v,不存在(u,v),则哈密顿路径不存在。

算法正确性证明:

​ 如果每一个顶点都和下一个顶点彼此相邻,那么拓扑排序的结果为我们提供了一条哈密顿路径。如果有一个顶点和下一个顶点彼此不相邻,由拓扑排序的性质可知,不存在任何路径使两顶点相邻,于是不会存在哈密顿路径。

​ 为了说明拓扑排序中相邻的顶点u和v,如果在图中不相邻(即没有(u,v))便不存在从u到v的路径,采用反证法:假设存在从u到v的路径,沿着这条上的任何顶点,它们必然在u之后v之前,那么根据拓扑排序它们应该在u和v之间,这与u和v 在拓扑排序结果中相邻矛盾。因此, 不存在这样的路径。

c++实现

#include
#include
#include
#include
#include
#include
#include
using namespace std;
vector<set<int> > read_file(string file_name)
{
     
    ifstream infile;
    infile.open(file_name,ios::in);
    int nums; //number of vertexes
    infile>>nums;
    vector<set<int> >graph(nums);
    int a = 0,b = 0;
    while( !infile.eof())
    {
     
        infile >> a >> b;
        graph[a].insert(b);
    }
    infile.close();
    return graph;
}

bool judge(vector<set<int> >&G,list<int>ans)
{
     
    for(list<int>::iterator it = ans.begin();it!=ans.end();it++)
    {
     
        list<int>::iterator next = it;
        next++;
        if(next == ans.end() )return true;
        if(!G[*it].count(*next) )
        {
     
            return false;
        }
    }
    return true;//make g++ happy
}

void output(vector<set<int> >&G,list<int>ans,int i)
{
     
    //redirect
    string file_name = "ans" + to_string(i)+".txt";
    ofstream fout;
    fout.open(file_name,ios::out);

    if(judge(G,ans) == 0)
    {
     
        fout<<0<<endl;
        
        return;
    }
    fout<<1<<endl;
    for(list<int>::iterator it = ans.begin();it != ans.end();it++)
    {
     
        fout << *it<<' ';
    }
    fout.close();
    return;
}

void DFS_visit(vector<set<int> >&G,int u,vector<int>&color,list<int>&ans)
{
     
    int size = G[u].size();
    for(auto it:G[u])
    {
     
        if(color[it] == 0)
            DFS_visit(G,it,color,ans);
    }
    color[u] = 1;

    ans.push_front(u);
}

void DFS(vector<set<int> >&G,list<int>&ans)
{
     
    int size = G.size();
    vector<int>color(size,0);//0 denotes white; 1 denotes black

    for(int i = 0;i < size;i++)
    {
     
        if(color[i] == 0)
        {
     
            DFS_visit(G,i,color,ans);
        }
    }
}

list<int> topological_sort(vector<set<int> >&G)
{
     
    list<int> ans;
    DFS(G,ans);
    return ans;
}

int main(int argc, char const *argv[])
{
     
    for(int i = 1;i < argc;i++)
    {
     
        string file_name = argv[i];
        vector<set<int> >graph = read_file(file_name);
        time_t start = clock();
        list<int> res =  topological_sort(graph);
        time_t end = clock();
        cout << "Compute dataset"<<i<<" costs " << (double)(end - start) *1000 / CLOCKS_PER_SEC << " ms" << endl;
        output(graph,res,i);
    }
    return 0;
}

代码使用说明

输入文件为图数据,第一行为节点数,之后每行表示一条边,节点编号从0开始。
输出文件第一行0表示没有哈密顿路径,1表示有哈密顿路径。如果有路径的话,第二行输出具体路径。
Example 1:
Input:
5
0 1
1 2
2 3
3 4
Output:
1
0 1 2 3 4

Example 2:
Input:
5
0 1
1 0
2 3
3 4
Output:
0

你可能感兴趣的:(算法,c++)