最短路 hdu 3499 Flight

最短路 hdu 3499 Flight
//最短路 hdu 3499 Flight



//最短路

//题意:给出n个地点,m条有向带权边,给出起点和终点,可以把

//其中一条边的权值减少一半,求起点到终点的最短路



//思路:分别求起点到各个点的最短路 和 终点到各个点的最短路(要用反向边)

//当然,把最短路存放在dis数组里,正向为dis1,方向为dis2

//然后循环每条边,求出每一边起点的dis1和每一边终点的dis2 还有该边的权值的一半 的和

//记录最小值就是答案了



//注意:

//1、如果是用优先队列优化dijsktra时,要记住放入队列里的不仅仅是点的下标,

//   还要有起点到该点的dis,然后根据dis从小到大排序

//2、优先队列重载的是 小于号'<' 而不是 大于号 '>'

//3、如果反向边是用另一个结构体数组保存则邻接表加边时只需++tot一次

//4、存储边的三个数组要都为500005而不是100005

//5、ios::sync_with_stdio(false); 记住有这句存在的情况下不要用stdio里的输入输出

//在没有这句的函数里好像可以



#include <stdio.h>

#include <cstring>

#include <string>

#include <queue>

#include <map>

#include <algorithm>

#include <iostream>



using namespace std;



#define comein freopen("in.txt", "r", stdin);

#define N 100005

#define M 500005

#define eps 1e-5



int tot;

int head[2][N];

int start[M], end[M], price[M]; //存储边

__int64 dis1[N], dis2[N];

bool vis[N];



struct EDGE

{

    int to, next;

    int dis;

}edge[2][M];



//struct POINT

//{

//    int pos;

//    __int64 dis;

//    POINT(){}

//    POINT(int p, __int64 d)

//    {

//        this->pos = p;

//        this->dis = d;

//    }

//    bool operator < (const POINT &a)const

//    {

//        return this->dis > a.dis;

//    }

//};

//

//

//void dijsktra(int root, int st, __int64 *dis)

//{

//    memset(vis, false, sizeof(vis));  //优先队列优化

//    priority_queue<POINT> que;      //这里优先队列不仅要存下标,还要存dis,要不没按dis排序

//    dis[st] = 0;          //到某一点不一定是最短路,可能有多个点到达pos,然后把这些边排序下

//    int now = st;

//    while(1)

//    {

//        vis[now] = true;

//        for(int i = head[root][now]; i != -1; i = edge[root][i].next)

//        {

//            int to = edge[root][i].to;

//            if(vis[to] == false && (dis[to] == -1 || dis[to] > edge[root][i].dis + dis[now]))

//            {

//                dis[to] = dis[now] + edge[root][i].dis;

//                que.push(POINT(to, dis[to]));

//            }

//        }

//        int tmp_pos = now;

//        while(!que.empty())

//        {

//            POINT tmp = que.top();

//            que.pop();

//            if(vis[tmp.pos] == false)

//            {

//                now = tmp.pos;

//                break;

//            }

//        }

//        if(tmp_pos == now)

//            break;

//    }

//}



void add_edge(int from, int to, int d, int edgeCnt)

{

    edge[0][++tot].to = to;     //这里tot前要++,下面就不要了,因为这是二维的

    edge[0][tot].dis = d;

    edge[0][tot].next = head[0][from];

    head[0][from] = tot;



    edge[1][tot].to = from;         //建逆邻接表

    edge[1][tot].dis = d;

    edge[1][tot].next = head[1][to];

    head[1][to] = tot;



    start[edgeCnt] = from;      //存储边

    end[edgeCnt] = to;

    price[edgeCnt] = d;

}

void spfa(int root, int st, __int64 *dis) //root标记是求正向还是反向的

{

    memset(vis, false ,sizeof(vis));

    queue<int> que;



    que.push(st);

    vis[st] = true; //标志是否入队了

    dis[st] = 0;

    while(!que.empty())

    {

        int now = que.front();

        que.pop();

        for(int i = head[root][now]; i != -1; i = edge[root][i].next)

        {

            int to = edge[root][i].to;

            int d = edge[root][i].dis;

            if( dis[to] == -1 || dis[to] - d > dis[now])

            {

                dis[to] = d + dis[now];

                if(vis[to] == false )

                {

                    que.push(to);

                    vis[to] = true;

                }



            }

        }

        vis[now] = false;       //出队的点要重新标记为false

    }

}





int main()

{

    comein

    //后面不能用puts("-1"),为了找到这个错误,花了我一天多的时间

    ios::sync_with_stdio(false);//不过本来是用spfa的,以为这算法不行,就第一次用优先队列

    int n_city, n_flight;       //优化了dijsktra,发现推进队列的能仅仅是点的下标,还要有dis

    while(cin >> n_city >> n_flight)    //才能根据dis来排序

    {

        tot = 0;

        map<string, int> mp;

        memset(head, -1, sizeof(head));

        int cnt = 0, d;



        string from, to;

        for(int i = 0; i < n_flight; ++i)

        {

            cin >> from >> to >> d;

            if(mp[from] == 0) mp[from] = ++cnt;

            if(mp[to] == 0) mp[to] = ++cnt;



            add_edge(mp[from], mp[to], d, i);

        }

        cin >> from >> to;



        if(mp[from] == 0 || mp[to] == 0)

            cout << -1 << endl;

        else

        {

            int st = mp[from], ed = mp[to];

            memset(dis1, -1, sizeof(dis1));

            spfa(0, st, dis1);    //正向找st到各点的最短路

//            dijsktra(0, st, dis1);

            if(dis1[ed] == -1)   //不可到达

                cout << -1 << endl;

            else

            {

                __int64 ans = (__int64)1<<60;

                memset(dis2, -1, sizeof(dis2));

                spfa(1, ed, dis2);    //反向找ed到各点的最短路

//                dijsktra(1, ed, dis2);



                for(int i = 0; i < n_flight; ++i)

                    ans = min(ans, dis1[start[i]] + dis2[end[i]] + price[i]/2);



                cout << ans << endl;

            }

        }

    }

    return 0;

}

 

你可能感兴趣的:(HDU)