pku 3255 Roadblocks 第二短路

http://poj.org/problem?id=3255 

题意:

给你一张图,起点为1,终点为n 。求从1到n的次短路。(这里每条边可以重复走)

思路:

两遍最短路算法分别求出1到所有点的最短距离,n到所有点的最短距离。然后枚举每一条边找出第二短路。

 

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)

#define ll long long
#define inf 0x7f7f7f7f
#define MOD 1073741824
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 200004
#define N 5007
using namespace std;
//freopen("din.txt","r",stdin);
struct node
{
    int v,w;
    int next;
}g[M];
int head[N],ct;

int dis1[N],dis2[N];
bool vt[N];
int n,m;

void add(int u,int v, int w)
{
    g[ct].v = v;
    g[ct].w = w;
    g[ct].next = head[u];
    head[u] = ct++;

    g[ct].v = u;
    g[ct].w = w;
    g[ct].next = head[v];
    head[v] = ct++;
}
void spfa1(int s)
{
    int i;
    for (i = 0; i < n; ++i)
    {
        dis1[i] = inf;
        vt[i] = false;
    }
    dis1[s] = 0; vt[s] = true;
    queue<int>q;
    q.push(s);
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        for (i = head[u]; i != -1; i = g[i].next)
        {
            int v = g[i].v;
            int w = g[i].w;
            //printf("%d %d\n",u,v);
            if (dis1[v] > dis1[u] + w)
            {
                dis1[v] = dis1[u] + w;
                if (!vt[v])
                {
                    vt[v] = true;
                    q.push(v);
                }
            }
        }

    }
}
void spfa2(int s)
{
    int i;
    for (i = 0; i < n; ++i)
    {
        dis2[i] = inf;
        vt[i] = false;
    }
    dis2[s] = 0; vt[s] = true;
    queue<int>q;
    q.push(s);
    while (!q.empty())
    {
        int u = q.front();  q.pop();
        for (i = head[u]; i != -1; i = g[i].next)
        {
            int v = g[i].v;
            int w = g[i].w;
            if (dis2[v] > dis2[u] + w)
            {
                dis2[v] = dis2[u] + w;
                if (!vt[v])
                {
                    vt[v] = true;
                    q.push(v);
                }
            }
        }
    }
}
int main()
{
    freopen("din.txt","r",stdin);
    int i,j;
    int x,y,z;
    while (~scanf("%d%d",&n,&m))
    {
        CL(head,-1); ct = 0;
        for (i = 0; i < m; ++i)
        {
            scanf("%d%d%d",&x,&y,&z);
            add(x - 1,y - 1,z);
        }
        //printf("ZUIDUANLU =  %d\n",dis1[n - 1]);
        spfa1(0);
        //printf("ZUIDUANLU =  %d\n",dis1[n - 1]);
        spfa2(n - 1);

        //printf("%d %d\n",dis1[n - 1],dis2[0]);
        int minB = inf;
        int minA = inf;
        for (i = 0; i < n; ++i)
        {
            for (j = head[i]; j != -1; j = g[j].next)
            {
                int v = g[j].v;
                int w = g[j].w;
                int m = dis1[i] + dis2[v] + w;
                int tmp = 0;
                //这样枚举才对 minA存的最短路径
                if (minA > m)
                {
                    tmp = minA;
                    minA = m;
                    m = tmp;
                }//minB存的第二短路径
                if (minB > m && m != minA)
                {
                    minB = m;
                }
                //不知道为什么这样枚举就错了.....
                /*if (dis1[n - 1] < dis1[i] + dis2[v] + w)
                {
                    disMax = min(disMax,dis1[i] + dis2[v] + w);
                }*/
            }
        }
        printf("%d\n",minB);
    }
    return 0;
}

  

 第二种思路:dis[i][0]表示最短路   dis[i][1]表示次短路  然后一边SPFA 队列里存放来自最短路或者次短路的点的值,然后更新最短路或者次短路。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)

#define ll long long
#define inf 0x7f7f7f7f
#define MOD 1073741824
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 200004
#define N 5007
using namespace std;
//freopen("din.txt","r",stdin);
struct node
{
    int v,w;
    int next;
}g[M];
int head[N],ct;

struct t_node
{
    int x,dis;
}p1,p2;

int dis[N][2];
bool vt[N][2];
int n,m;

void add(int u,int v,int w)
{
    g[ct].v = v;
    g[ct].w = w;
    g[ct].next = head[u];
    head[u] = ct++;

    g[ct].v = u;
    g[ct].w = w;
    g[ct].next = head[v];
    head[v] = ct++;
}
void spfa(int s)
{
    int i;
    for (i = 1; i <= n; ++i)
    {
        dis[i][0] = dis[i][1] = inf;
    }
    dis[s][0] = 0;

    queue<t_node>q;
    p1.x = s;
    p1.dis = 0;
    q.push(p1);

    while (!q.empty())
    {
        p2 = q.front(); q.pop();
        int u = p2.x;

        for (i = head[u]; i != -1; i = g[i].next)
        {
            int v = g[i].v;
            int w = p2.dis + g[i].w;

            if (dis[v][0] > w)//更新最短路
            {
                if (dis[v][0] != inf)//更新次短路
                {
                    dis[v][1] = dis[v][0];
                    p1.dis = dis[v][1];
                    p1.x = v;
                    q.push(p1);
                }
                dis[v][0] = w;
                p1.dis = w;
                p1.x = v;
                q.push(p1);
            }
            else if (dis[v][1] > w)//更新次短路
            {
                dis[v][1] = w;
                p1.dis = w;
                p1.x = v;
                q.push(p1);
            }
        }
    }
}
int main()
{
    //freopen("din.txt","r",stdin);
    int i;
    int x,y,z;
    while (~scanf("%d%d",&n,&m))
    {
        CL(head,-1); ct = 0;
        for (i = 0; i < m; ++i)
        {
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
        }
        spfa(1);
       // printf("<><>%d\n",dis[n][0]);
        //for (i = 1; i <= n; ++i)
        printf("%d\n",dis[n][1]);
    }
    return 0;
}

  

 第三种思路:

求第K短路通用算法最短路+A*启发式搜索

(注:以下部份资料来源于网上)

所谓A*就是启发是搜索 说白了就是给搜索一个顺序使得搜索更加合理减少无谓的搜索. 如何来确定搜索的顺序?..也就是用一个值来表示 这个值为f[n]..每次搜索取f[x]最小的拓展 那么这个f[n]=h[n]+g[n]
其中f(n) 是节点n的估价函数,g(n)是在状态空间中从初始节点到n节点的实际代价,h(n)是从n到目标节点最佳路径的估计代价。在这里主要是h(n)体现了搜索的启发信息,因为g(n)是已知的。如果说详细 点,g(n)代表了搜索的广度的优先趋势。但是当h(n) >> g(n)时,可以省略g(n),而提高效率。

A*算法的估价函数可表示为:   
  f’(n) = g’(n) + h’(n)   
这里,f’(n)是估价函数,g’(n)是起点到终点的最短路径值,h’(n)n到目标的最短路经的启发值。由 于这个f’(n)其实是无法预先知道的,所以我们用前面的估价函数f(n)做近似。g(n)代替g’(n),但 g(n)>=g’(n) 才可(大多数情况下都是满足的,可以不用考虑),h(n)代替h’(n),但h(n)<=h’(n)才可(这一点特别的重 要)。可以证明应用这样的估价函数是可以找到最短路径的,也就是可采纳的。我们说应用这种估价函数的最好优先算法就是A*算法。

 

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)

#define ll long long
#define inf 0x7f7f7f7f
#define MOD 1073741824
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 200004
#define N 5007
using namespace std;
//freopen("din.txt","r",stdin);
struct node
{
    int v,w;
    int next;
}g[M];
int head[N],ct;

int dis[N];
bool vt[N];
int n,m;

struct A_node
{
    int v,g;
    bool operator < (A_node b) const
    {
        return (g + dis[v]) > (b.g + dis[b.v]);
    }
}p1,p2;



void add(int u,int v,int w)
{
    g[ct].v = v;
    g[ct].w = w;
    g[ct].next = head[u];
    head[u] = ct++;

    g[ct].v = u;
    g[ct].w = w;
    g[ct].next = head[v];
    head[v] = ct++;
}

void spfa(int s)
{
    int i;
    for (i = 1; i <= n; ++i)
    {
        dis[i] = inf;
        vt[i] =false;
    }
    dis[s] = 0; vt[s] = true;
    queue<int>q;
    q.push(s);
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        vt[u] = false;
        for (i = head[u]; i != - 1; i = g[i].next)
        {
            int v = g[i].v;
            int w = g[i].w;
            if (dis[v] > dis[u] + w)
            {
                dis[v] = dis[u] + w;
                if (!vt[v])
                {
                    vt[v] = true;
                    q.push(v);
                }
            }
        }
    }
}

int cnt[N];
priority_queue<A_node> pq;

int A_star(int s,int t,int k)
{
    int i;
    int ans = 0;
    CL(cnt,0);
    while (!pq.empty()) pq.pop();

    if (s == t) k++;//注意当s==t时需要计算K+1短路,因为s到t这条距离为0的路不能算在这K短路中,这时只需将K++
    p1.g = 0; p1.v = s;
    pq.push(p1);
    while (!pq.empty())
    {
        p2 = pq.top(); pq.pop();
        int u = p2.v;
        int gi = p2.g;
        cnt[u]++;
        if (cnt[u] > k) continue;
        if (cnt[t] == k)
        {
            ans = gi;
            break;
        }

        for (i = head[u]; i != -1; i = g[i].next)
        {
            int v = g[i].v;
            int w = g[i].w;
            p1.v = v; p1.g = gi + w;
            pq.push(p1);
        }
    }
    return ans;
}

int main()
{
    //freopen("din.txt","r",stdin);
    int i;
    int x,y,z;
    while (~scanf("%d%d",&n,&m))
    {
        CL(head,-1); ct = 0;
        for (i = 0; i < m; ++i)
        {
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
        }
        spfa(n);
        printf("%d\n",A_star(1,n,2));
    }
    return 0;
}

 

  

 

 

 

 

posted @ 2013-01-22 16:29  E_star  阅读(409)  评论(0编辑  收藏  举报