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;

}

 

  

 

 

 

 

你可能感兴趣的:(block)