【问题标题】:Priority queue in Dijkstra's algorithmDijkstra 算法中的优先级队列
【发布时间】:2013-07-27 13:29:35
【问题描述】:

这是我的 Dijkstra 算法代码:

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>

#define pp pair<int,int>
using namespace std;
struct pri
{
    int operator() (const pair<int,int>&p1,const pair<int,int>&p2)
    {
        return p1.second<p2.second;
    }
}p;
int main()
{
    priority_queue<pp,vector<pp>,pri> q;
    int n;
    cin>>n;
    vector<pp> g[n+1];
    int e,u,v,w,i;
    cin>>e;
    for(i=0;i<e;i++)
    {
        cin>>u>>v>>w;
        g[u].push_back(pp(v,w));
        g[v].push_back(pp(u,w));
    }
    int s;
    cin>>s;
    int d[n+1];
    for(i=1;i<=n;i++)
        d[i]=999;
    d[s]=0;
    q.push(pp(s,d[s]));
    while(!q.empty())
    {
        u=q.top().first;
        q.pop();
        int size=g[u].size();
        for(int i=0;i<size;i++)
        {
            v=g[u][i].first;
            w=g[u][i].second;
            cout<<u<<" "<<" "<<w<<endl;
            if(d[v]>d[u]+w)
            {
                d[v]=d[u]+w;
                q.push(pp(v,d[v]));
            }
        }
    }
    for(i=1;i<=n;i++)
        printf("node %d,min weight=%d\n",i,d[i]);
    return 0;
}

在这我无法理解的工作

 priority_queue<pp,vector<pp>,pri> q;

这与:

struct pri
{
    int operator() (const pair<int,int>&p1,const pair<int,int>&p2)
    {
        return p1.second<p2.second;
    }
}p;

() 运算符在这有什么用?我的意思是它在这段代码中是如何工作的?

还有为什么我们在operator() 中使用&amp;

另外,这个比较器在优先级队列定义中是如何工作的? 为什么我们在运算符定义中使用常量?

我的意思是说这种比较在操作员工作中到底是如何工作的,我们不能使用任何 其他符号为 = * @ 或任何其他符号,而不是 ()

【问题讨论】:

  • 请正确缩进。

标签: c++ algorithm dijkstra


【解决方案1】:

我认为你写的比较函数是错误的。

int operator() (const pair<int,int>&p1,const pair<int,int>&p2)
{
    return p1.second<p2.second;
}

哪个是正确的

int operator() (const pair<int,int>&p1,const pair<int,int>&p2)
{
    return p1.second>p2.second;
}

因为在priority_queque你可以找到表达式comp(a,b),其中comp是这种类型的对象,a和b是容器中的元素,如果a被认为在b之前应该返回true在函数定义的严格弱排序中。

因为在Dijkstra算法中,值较小的节点应该具有较高的优先级,所以我们这里使用的算子应该是

p1.second>p2.second

(通过使用您的代码解决问题,我花了很长时间才弄清楚这个问题,我的程序的结果总是与正确的结果不同。) (顺便说一下,在 Dijkstra 算法本身中,我认为一旦一个节点被弹出为最小的节点,就没有必要再次弹出它并更新与其连接的所有节点。这样可以节省很多时间。)

【讨论】:

    【解决方案2】:
    struct pri {
        int operator() (const pair<int,int>&p1,const pair<int,int>&p2)
        {
            return p1.second<p2.second;
        }
    }p;
    

    通过重载() 运算符创建function object

    这作为比较类传递给priority_queue

    &amp; 用于将pair 作为常量引用传递,确保不会复制实际参数(通过将它们作为引用传递),同时函数不能修改它们的值(通过使用const关键字)

    使用这个函数对象,队列决定如何插入值(对)。

    在这种情况下,pair 的第二个值用于比较。

    【讨论】:

      【解决方案3】:

      在声明变量(包括函数参数)时,&amp; 就是将变量标记为引用。对某些类型的参数使用引用是非常基本和常见的事情,部分原因是它在不创建副本的情况下传递参数(例如std::vector),它还允许在函数中更改非常量引用作为输出参数的形式。

      至于在这样的结构中使用operator(),它会生成结构function objects的实例,换句话说,可以像函数一样调用的对象。

      【讨论】:

        【解决方案4】:

        我想你的问题是关于priority_queue&lt;pp,vector&lt;pp&gt;,pri&gt; q;这行?

        这声明了一个priority_queue&lt;pp,vector&lt;pp&gt;,pri&gt; 类型的变量qpriority_queue 定义为

        template<class T,
                 class Container = vector<T>,
                 class Compare = less<typename Container::value_type> >
        class priority_queue;
        

        所以,pp 是元素的类型,vector&lt;pp&gt; 是容器(与默认相同),pri 是一个函数对象,用于比较队列中的项目(Compare )。 priority_queue 使用 Compare 对其元素进行排序。如果元素不能直接比较,或者默认值不合适,那么您可以提供自己的。在这种情况下,元素将按每个元素pair 中的second 成员排序。

        【讨论】:

        【解决方案5】:

        与其他答案基本相同,只是更详细一点——operator() 代码定义了优先级队列应如何进行比较以确定队列中的项目优先级。使用这种类型的框架,您可以定义一个优先级队列来存储任何类型的对象,并且可以根据您想要的对象上的任何类型的自定义排序来对优先级队列进行排序。

        【讨论】:

          【解决方案6】:

          我重构了这段代码并用hackerrank检查了它。

          #include <cstdio>
          #include <vector>
          #include <queue>
          #include <iostream>
          #include <vector>
          #include <deque>
          #include <set>
          #include <limits>
          #include <iterator>
          #include <algorithm>
          #include <functional>
          
          using namespace std;
          
          struct pri
          {
              typedef pair<int,int> pp;
              typedef deque<pri::pp > list;
              typedef vector< pri::list > graph;
              int operator() (pp&p1,const pp&p2)
              {
                  return p1.second>p2.second;
              }
              typedef priority_queue< pri::pp, pri::list, pri > queue;
          };
          
          static int f1(const int x){ return x==std::numeric_limits<int>().max()?-1:x; }
          
          int main()
          {
              int t;
              cin>>t;
              while(t--){
                  int n,e;
                  cin>>n>>e;
                  pri::graph g(n+1);
                  for(int i(0);i<e;i++){
                      int u,v,w;
                      cin>>u>>v>>w;
                      g[u].push_back(pri::pp(v,w));
                      g[v].push_back(pri::pp(u,w));
                  }
                  vector<int> d(n+1,std::numeric_limits<int>().max());
                  int s;        cin>>s;
                  d[s]=0;
                  pri::queue q;
                  q.push(pri::pp(s,d[s]));
                  set<int> vs;
                  while(!q.empty()) {
                      const int u(q.top().first);
                      const pri::list& gu(g[u]);
                      q.pop();
                      vs.insert(u);
                      for( pri::list::const_iterator i(gu.begin()); i != gu.end(); ++i ) {
                          const int v(i->first),  w(i->second);
                          if( vs.find(v)==vs.end() ){
          //                  cout<<u<<" "<<v<<" "<<w<<endl;
                              if( d[v]>d[u]+w ) {
                                  d[v]=d[u]+w;
                                  q.push(pri::pp(v,d[v]));
                              }
                          }
                      }
                  }
                  copy_if(d.begin()+1,d.end(),d.begin(),std::bind2nd(std::not_equal_to<int>(),0));
                  transform(d.begin(),d.end()-2,ostream_iterator<int>(cout," "),f1);
                  cout<<endl;
              }
              return 0;
          }
          

          【讨论】:

            猜你喜欢
            • 2013-12-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多