HDU6181-Two Paths【A*算法or次短路】

Two Paths

Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 153428/153428 K (Java/Others)
Total Submission(s): 190 Accepted Submission(s): 113

Problem Description
You are given a undirected graph with n nodes (numbered from 1 to n) and m edges. Alice and Bob are now trying to play a game.
Both of them will take different route from 1 to n (not necessary simple).
Alice always moves first and she is so clever that take one of the shortest path from 1 to n.
Now is the Bob’s turn. Help Bob to take possible shortest route from 1 to n.
There’s neither multiple edges nor self-loops.
Two paths S and T are considered different if and only if there is an integer i, so that the i-th edge of S is not the same as the i-th edge of T or one of them doesn’t exist.

Input
The first line of input contains an integer T(1 <= T <= 15), the number of test cases.
The first line of each test case contains 2 integers n, m (2 <= n, m <= 100000), number of nodes and number of edges. Each of the next m lines contains 3 integers a, b, w (1 <= a, b <= n, 1 <= w <= 1000000000), this means that there’s an edge between node a and node b and its length is w.
It is guaranteed that there is at least one path from 1 to n.
Sum of n over all test cases is less than 250000 and sum of m over all test cases is less than 350000.

Output
For each test case print length of valid shortest path in one line.

Sample Input
2
3 3
1 2 1
2 3 4
1 3 3
2 1
1 2 1

Sample Output
5
3
Hint

For testcase 1, Alice take path 1 - 3 and its length is 3, and then Bob will take path 1 - 2 - 3 and its length is 5.
For testcase 2, Bob will take route 1 - 2 - 1 - 2 and its length is 3

Source
2017 Multi-University Training Contest - Team 10

题目大意: 1 n的次短路。
解题思路: A 算法可以用来求第 k 短路,当然也可以用来求次短路。
k短路可以理解为第 k 次走到终点,那就相当于是终点被找到k次,即出队 k 次。利用A算法,首先求出其他点到 des 的最短距离,然后用基于 BFS 的优先队列 A 算法求 f(i)=g(i)+h(i) ,其中 h(i) 表示 i des的最短路, g(i) 表示从 src i 的路径长度,每次取出f(i)值最小的,当第 k 次取出t时即求出第 k 短路。
注: A算法的题目可以看POJ2449

另解:此题也可以直接用求次短路的方法(在 Dijkstra 上进行少许修改)解决。到某个顶点 v 的次短路要么是到其他某个顶点u的最短路再加上 uv 的边,要么是到 u 的次短路再加上uv的边。对于每个顶点,我们记录的不仅仅是最短距离,还有次短距离。在跑 Dijkstra 时,不断更新这两个距离即可。
注:次短路算法的题目可以看POJ3255

A 解法:

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
typedef long long LL;
const LL INF=1e18;
const int MAXN=1e5+5;
int head[MAXN],head1[MAXN];
LL dis[MAXN];
bool vis[MAXN];
int n,m,tot,st,en,k;

struct Edge
{
    int u,v,nxt,nxt1;
    LL c;
    Edge(){}
    Edge(int _u,int _v,LL _c):u(_u),v(_v),c(_c){}
}e[MAXN*2];

struct qnode
{
    int v;
    LL c;
    qnode(){}
    qnode(int _v,LL _c):v(_v),c(_c){}
    bool operator < (const qnode& rhs) const
    {
        return c+dis[v]>rhs.c+dis[rhs.v];
    }
};

void addedge(int u,int v,LL c)
{
    e[tot]=Edge(u,v,c);
    e[tot].nxt=head[u];head[u]=tot;
    e[tot].nxt1=head1[v];head1[v]=tot++;
}

void dij(int src)
{
    memset(vis,false,sizeof(vis));
    for(int i=1;i<=n;i++) dis[i]=INF;
    dis[src]=0;
    priority_queue<qnode> que;
    que.push(qnode(src,0));
    while(!que.empty())
    {
        qnode pre=que.top(); que.pop();
        if(vis[pre.v]) continue;
        vis[pre.v]=true;
        for(int i=head1[pre.v];i!=-1;i=e[i].nxt1)
        {
            if(dis[e[i].u]>dis[pre.v]+e[i].c)
            {
                dis[e[i].u]=dis[pre.v]+e[i].c;
                que.push(qnode(e[i].u,0));
            }
        }
    }
}

LL a_star(int src)
{
    priority_queue<qnode> que;
    que.push(qnode(src,0));
    k--;
    while(!que.empty())
    {
        qnode pre=que.top();que.pop();
        if(pre.v==en)
        {
            if(k) k--;
            else return pre.c;
        }
        for(int i=head[pre.v];i!=-1;i=e[i].nxt)
            que.push(qnode(e[i].v,pre.c+e[i].c));
    }
    return -1;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        memset(head,-1,sizeof(head));
        memset(head1,-1,sizeof(head1));
        tot=0;
        for(int i=0;i<m;i++)
        {
            int u,v;LL c;
            scanf("%d%d%lld",&u,&v,&c);
            addedge(u,v,c);
            addedge(v,u,c);
        }
        st=1,en=n;k=2;
        dij(en);
        if(st==en) k++;
        printf("%lld\n",a_star(st));
    }
    return 0;
}

次短路解法:

///求次短路
///使用优先队列Dijkstra算法
///复杂度O(ElogV)
///注意初始化
///dist2[v]=min(dist[u]+e(u,v),dist2[u]+e(u,v))
#include<iostream>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<map>
#include<cstring>
#include<string>
#include<set>
#include<queue>
#include<fstream>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int MAXN=1e5+5;
const int MAXM=2e5+5;
const LL INF=1e18;
LL dist[MAXN];
int head[MAXN],tot;
LL dist2[MAXN];//次短距离
int pre[MAXN];

struct Edge
{
    int from,to,nxt;
    LL cost;
    Edge(){}
    Edge(int _from,int _to,LL _cost):from(_from),to(_to),cost(_cost){}
}e[MAXM];

void addedge(int u,int v,int w)
{
    e[tot].from=u;e[tot].to=v;e[tot].cost=w;
    e[tot].nxt=head[u];head[u]=tot++;
}

struct qnode
{
    int v;
    LL c;
    qnode(LL _c=0,int _v=0):c(_c),v(_v){}
    bool operator < (const qnode &rhs) const {return c>rhs.c;}
};

void Dijkstra(int n,int st)//点的编号从1开始
{
    for(int i=0;i<=n;i++) dist[i]=INF,dist2[i]=INF;
    priority_queue<qnode> pq;
    while(!pq.empty()) pq.pop();
    dist[st]=0;
    pq.push(qnode(0,st));
    qnode frt;
    while(!pq.empty())
    {
        frt=pq.top(); pq.pop();
        int u=frt.v;
        LL d=frt.c;
        if(dist2[u]<d) continue;
        for(int i=head[u];i!=-1;i=e[i].nxt)
        {
            int to=e[i].to;
            LL cost=e[i].cost;
            LL d2=d+cost;
            if(dist[to]>d2)
            {
                swap(dist[to],d2);
                pre[to]=u;
                pq.push(qnode(dist[to],to));
            }
            if(dist2[to]>d2&&dist[to]<d2)
            {
                dist2[to]=d2;
                pq.push(qnode(dist2[to],to));
            }
        }
    }
}

int main()
{
    int T;
    int vN,eN;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&vN,&eN);
        tot=0;memset(head,-1,sizeof(head));
        int u,v,w;
        for(int i=1;i<=eN;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);addedge(v,u,w);
        }
        int st,ed;
        st=1,ed=vN;
        //scanf("%d%d",&st,&ed);
        //if(st==ed) {printf("0\n");continue;}
        Dijkstra(vN,st);
//        for(int i=0;i<=vN-1;i++)
//            printf("%d ",dist[i]);
//        printf("\n");
//        for(int i=0;i<=vN-1;i++)
//            printf("%d ",pre[i]);
//        printf("\n");
        printf("%lld\n",dist2[ed]);
    }
    return 0;
}
/*
1
4 6
1 2 1
1 2 5
1 3 2
2 3 2
2 4 1
2 4 6

ans:4
*/
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值