poj 2449 Remmarguts' Date

 

第K短路问题,可以用A*来写,我了个去,遇到了超级令人无语的错误...

    如何求第K短呢?有一种简单的方法是广度优先搜索,记录t出队列的次数,当t第k次出队列时,就是第k短路了。但点数过大时,入队列的节点过多,时间和空间复杂度都较高。

现在有另一种更加高效的算法A*。

 

介绍一些关键的概念:
首先,对于状态空间搜索,是可以提出一个通用的搜索算法框架的,而这个框架中则主要使用了open,和closed两个表。open表,保存了当前待扩展节点,closed表则保存已扩展节点,而BFS DFS也可以纳入这个框架,比如DFS中使用的white black gray染色,实际于 open closed便是对应的。

对于启发式搜索一般具有如下评估函数f*(n) = g*(n)+h*(n),f*(n)表示从起始点经过n到达目标的估计函数。

g*(n)表示从起始点到达节点n的花费函数,比如对于最短路问题,可能就是已经发现的从出发点,到当前节点的最小cost,h*(n)表示从当前状态n到目标状态的估计花费。

对于h*(n)施加如下约束,g*(n) >= g(n)  ,h*(n) <= h(n),即估计花费从是小于等于实际最小花费,则启发式搜索就是A*算法。而A*算法是可接纳的,也就是说如果存在一条到达目标的最优路径,A*算法可以保证找到这条路径。

继续对A*算法的h函数施加约束,可以保证满足一致性,或者叫单调性,约束是:对于任意的状态ni,nj
h*(ni) - h*(nj) <= c(ni,nj)
一致性可以保证,当 A*扩展节点n时,它已经找到了到达节点n的最优路径。

 

相关资料:

http://duanple.blog.163.com/blog/static/70971767200811344425606/

http://blog.csdn.net/bmexue/article/details/6967027

http://related.doc88.com/related%2F%E5%90%AF%E5%8F%91%E5%BC%8F%E6%90%9C%E7%B4%A2%5E492273006798%5E20120613094619_kLNtuj8u.html%5E75

http://www.doc88.com/p-34182603434.html

http://blog.csdn.net/emilmatthew/article/details/1338808

 

另外:启发式搜索有一个明显的缺点,就是以空间换取时间,可能会MLE,如果估价函数写的不好的话,可能速度快,但没有那么准确(估价系数是1.0是是最准确的,如果2.0、3.0可能速度快,但可能会影响结果),这就需要大家根据具体情况再考虑。

AC CODE:

CODE:

 

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <queue>
using  namespace std;

#define MAXM 100010
#define MAXN 1010
#define INF 0x3f3f3f3f

struct Edge
{
     int v, g, f;
     int next;
     bool  operator < ( const Edge &a)  const     // 结构体重载,如果在外面重载会MLE 
    {
         if(a.f == f)  return a.g < g;     // f = h + g, 此时h为t->s的最短路径。 
         else  return a.f < f;
    }
}edge[MAXM], edge2[MAXM];

/* bool operator < (const node a, const node b)   //这样重载会MLE,不知为啥
{
    if(a.f == b.f) return a.g < b.g;
    else return a.f < b.f;
}
*/  

int n, m, cnt;
int first[MAXN], first2[MAXN];
int d[MAXN], ct[MAXN];

void init()
{
    cnt =  0;
    memset(first, - 1sizeof(first));
    memset(first2, - 1sizeof(first2));
    memset(ct,  0sizeof(ct));
}

void read_graph( int u,  int v,  int w)
{
    edge[cnt].v = v, edge[cnt].g = w;
    edge[cnt].next = first[u], first[u] = cnt;
    edge2[cnt].v = u, edge2[cnt].g = w;
    edge2[cnt].next = first2[v], first2[v] = cnt++;
// 建立正、反向图。 

void spfa( int src)
{
    queue< int> q;
     bool inq[MAXN] = { 0};
     for( int i =  1; i <= n; i++) d[i] = (i == src)? 0:INF;
    q.push(src);
     while(!q.empty())
    {
         int x = q.front(); q.pop();
        inq[x] =  0, ct[x]++;
         if(ct[x] >= n)  return ;  // 存在负环 
         for( int e = first2[x]; e != - 1; e = edge2[e].next)
        {
             int v = edge2[e].v, w = edge2[e].g;
             if(d[v] > d[x] + w)
            {
                d[v] = d[x] + w;
                 if(!inq[v])
                {
                    inq[v] =  1;
                    q.push(v);
                }
            }
        }
    }
}

int A_STAR( int s,  int t,  int k)
{
     int tot =  0;  
     struct Edge cur, now;  
    priority_queue<Edge> Q;  
     if (s == t) k++;  
     if (d[s] == INF)  return - 1// 没有路径可达 
    cur.v = s, cur.g =  0, cur.f = d[s];
    Q.push(cur);  
     while(!Q.empty())
    {
        cur = Q.top(); Q.pop();
         if(cur.v == t)
        {
            tot++;  
             if(tot == k)  return cur.g;  
        } 
         for( int e = first[cur.v]; e != - 1; e = edge[e].next)
        {
             int v = edge[e].v, g = edge[e].g; 
            now.v = v, now.g = cur.g + g;  
            now.f = now.g + d[v];     // 更新g
            Q.push(now);  
        }
    }
     return - 1;  
}

int main()
{
     while(~scanf( " %d%d ", &n, &m))
    {
        init();
         while(m--)
        {
             int u, v, w;
            scanf( " %d%d%d ", &u, &v, &w);
            read_graph(u, v, w);
        }
         int s, e, k;
        scanf( " %d%d%d ", &s, &e, &k);
        spfa(e);
         int ans = A_STAR(s, e, k);
        printf( " %d\n ", ans);
    }
     return  0;
}

 

MLE CODE:

 

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <queue>
using  namespace std;

#define MAXM 100005
#define MAXN 1005
#define INF 0x3f3f3f3f

struct Edge
{
     int v, g, f;
     int next;
     /* bool operator < (const Edge &a) const    //结构体重载,如果在外面重载会MLE 
    {
        if(a.f == f) return a.g < g;    //f = h + g, 此时h为t->s的最短路径。 
        else return a.f < f;
    }
*/
}edge[MAXM], edge2[MAXM];

bool  operator < ( Edge a,  Edge b)    // 这样重载会MLE,不知为啥
{
     if(a.f == b.f)  return a.g < b.g;
     else  return a.f < b.f;
}

int n, m, cnt;
int first[MAXN], first2[MAXN];
int d[MAXN], ct[MAXN];

void init()
{
    cnt =  0;
    memset(first, - 1sizeof(first));
    memset(first2, - 1sizeof(first2));
    memset(ct,  0sizeof(ct));
}

void read_graph( int u,  int v,  int w)
{
    edge[cnt].v = v, edge[cnt].g = w;
    edge[cnt].next = first[u], first[u] = cnt;
    edge2[cnt].v = u, edge2[cnt].g = w;
    edge2[cnt].next = first2[v], first2[v] = cnt++;
// 建立正、反向图。 

void spfa( int src)
{
    queue< int> q;
     bool inq[MAXN] = { 0};
     for( int i =  1; i <= n; i++) d[i] = (i == src)? 0:INF;
    q.push(src);
     while(!q.empty())
    {
         int x = q.front(); q.pop();
        inq[x] =  0, ct[x]++;
         if(ct[x] >= n)  return ;  // 存在负环 
         for( int e = first2[x]; e != - 1; e = edge2[e].next)
        {
             int v = edge2[e].v, w = edge2[e].g;
             if(d[v] > d[x] + w)
            {
                d[v] = d[x] + w;
                 if(!inq[v])
                {
                    inq[v] =  1;
                    q.push(v);
                }
            }
        }
    }
}

int A_STAR( int s,  int t,  int k)
{
     int tot =  0;  
     struct Edge cur, now;  
    priority_queue<Edge> Q;
     if (s == t) k++;  
     if (d[s] == INF)  return - 1// 没有路径可达 
    cur.v = s, cur.g =  0, cur.f = d[s];
    Q.push(cur);  
     while(!Q.empty())
    {
        cur = Q.top(); Q.pop();
         if(cur.v == t)
        {
            tot++;  
             if(tot == k)  return cur.g;  
        } 
         for( int e = first[cur.v]; e != - 1; e = edge[e].next)
        {
             int v = edge[e].v, g = edge[e].g; 
            now.v = v, now.g = cur.g + g;  
            now.f = now.g + d[v];     // 更新g
            Q.push(now);  
        }
    }
     return - 1;  
}

int main()
{
     while(~scanf( " %d%d ", &n, &m))
    {
        init();
         while(m--)
        {
             int u, v, w;
            scanf( " %d%d%d ", &u, &v, &w);
            read_graph(u, v, w);
        }
         int s, e, k;
        scanf( " %d%d%d ", &s, &e, &k);
        spfa(e);
         int ans = A_STAR(s, e, k);
        printf( " %d\n ", ans);
    }
     return  0;
}

 

你可能感兴趣的:(Date)