最短路径专题

 1                       

                                           B - 一个人的旅行 HDU - 2066      

虽然草儿是个路痴(就是在杭电待了一年多,居然还会在校园里迷路的人,汗~),但是草儿仍然很喜欢旅行,因为在旅途中 会遇见很多人(白马王子,^0^),很多事,还能丰富自己的阅历,还可以看美丽的风景……草儿想去很多地方,她想要去东京铁塔看夜景,去威尼斯看电影,去阳明山上看海芋,去纽约纯粹看雪景,去巴黎喝咖啡写信,去北京探望孟姜女……眼看寒假就快到了,这么一大段时间,可不能浪费啊,一定要给自己好好的放个假,可是也不能荒废了训练啊,所以草儿决定在要在最短的时间去一个自己想去的地方!因为草儿的家在一个小镇上,没有火车经过,所以她只能去邻近的城市坐火车(好可怜啊~)。

Input

输入数据有多组,每组的第一行是三个整数T,S和D,表示有T条路,和草儿家相邻的城市的有S个,草儿想去的地方有D个; 
接着有T行,每行有三个整数a,b,time,表示a,b城市之间的车程是time小时;(1=<(a,b)<=1000;a,b 之间可能有多条路) 
接着的第T+1行有S个数,表示和草儿家相连的城市; 
接着的第T+2行有D个数,表示草儿想去地方。

Output

输出草儿能去某个喜欢的城市的最短时间。

Sample Input

6 2 3
1 3 5
1 4 7
2 8 12
3 8 4
4 9 12
9 10 2
1 2
8 9 10

Sample Output

9

单元最短路的扩展为一定的多源最短路,用Floyd的话恐怕会超时,我用了个 spfa 直接过,不过要注意 vector数组容量,因为是无向图,vector 要开2倍的边的数量

AC代码:

#include <iostream>
#include <queue>
#include <vector>
#include <cstring>

using namespace std;

typedef long long ll;

struct node
{
    int to,val;
    node(int _to=0,int _val=0){to=_to;val=_val;}
};

const int inf=1e9;

int dis[1005];
vector<node>vec[5005];

 int m;
void spfa(int s)
{
    //int cis[1005];
    int vis[1005];


    memset(vis,0,sizeof(vis));
    memset(dis,0x3f,sizeof(dis));

    queue<int>que;
    dis[s]=0;
    vis[s]=1;
   // cis[s]++;
    que.push(s);

    while (!que.empty())
    {
        int k=que.front();
        que.pop();
        vis[k]=0;
        for(int i=0;i<(int)vec[k].size();i++)
        {
            int v=vec[k][i].to;
            if(dis[v]>dis[k]+vec[k][i].val)
              {
               dis[v]=dis[k]+vec[k][i].val;

               if(vis[v]==0)
               {
                   vis[v]=1;
                  // cis[v]++;
                   que.push(v);
               }

              }
        }

    }


}
 int main()
{
   int s_num,t_num;

   while (cin >>m>>s_num>>t_num)
   {
     int ss[1005];
     int tt[1005];

     for(int i=0;i<1005;i++)
        vec[i].clear();

    for(int i=0;i<m;i++)
    {
        int a,b,c;
        cin >>a>>b>>c;
        vec[a].push_back(node(b,c));
        vec[b].push_back(node(a,c));
    }

    for(int i=0;i<s_num;i++)
    {   int a;
        cin >>a;
        ss[i]=a;
    }

    for(int i=0;i<t_num;i++)
    {
        int a;
        cin>>a;
         tt[i]=a;
    }

    int mins=inf;
    for(int i=0;i<s_num;i++)
    {
        spfa(ss[i]);
        for(int i=0;i<t_num;i++)
        {
            if(mins>dis[tt[i]])
            mins=dis[tt[i]];
        }

    }

    cout <<mins<< endl;
   }
    return 0;
}

2 upc

    

                                                  问题 B: Bumped!

                                                          时间限制: 1 Sec  内存限制: 128 MB
                                                                         提交: 373  解决: 48

题目描述

Peter returned from the recently held ACM ICPC World finals only to find that his return flight was overbooked and he was bumped from the flight! Well, at least he wasn’t beat up by the
airline and he’s received a voucher for one free flight between any two destinations he wishes.
He is already planning next year’s trip. He plans to travel by car where necessary, but he may be using his free flight ticket for one leg of the trip. He asked for your help in his planning.
He can provide you a network of cities connected by roads, the amount it costs to buy gas for traveling between pairs of cities, and a list of available flights between some of those cities. Help Peter by finding the minimum amount of money he needs to spend to get from his hometown to next year’s destination!

 

输入

The input consists of a single test case. The first line lists five space-separated integers n, m, f, s, and t, denoting the number of cities n (0 < n ≤ 50 000), the number of roads m (0 ≤ m ≤ 150 000), the number of flights f (0 ≤ f ≤ 1 000), the number s (0 ≤ s < n) of the city in which Peter’s trip starts, and the number t (0 ≤ t < n) of the city Peter is trying to travel to. (Cities are numbered from 0 to n − 1.)
The first line is followed by m lines, each describing one road. A road description contains three space-separated integers i, j, and c (0 ≤ i, j < n, i 6= j and 0 < c ≤ 50 000), indicating there is a road connecting cities i and j that costs c cents to travel. Roads can be used in either direction for the same cost. All road descriptions are unique.
Each of the following f lines contains a description of an available flight, which consists of two space-separated integers u and v (0 ≤ u, v < n, u 6= v) denoting that a flight from city u to city v is available (though not from v to u unless listed elsewhere). All flight descriptions are unique.

 

输出

Output the minimum number of cents Peter needs to spend to get from his home town to the competition,using at most one flight. You may assume that there is a route on which Peter can reach his destination.

样例输入

8 11 1 0 5
0 1 10
0 2 10
1 2 10
2 6 40
6 7 10
5 6 10
3 5 15
3 6 40
3 4 20
1 4 20
1 3 20
4 7

样例输出

45

题意:给出m个表(城市和城市以及之间的花费 开车!)和 f 张机票(可任意城市),只能用一张机票,用了之后,两个城市之间的花费变为0,问最少花费是多少?

spfa+单个修改

#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
#define MAX 50000+6

typedef long long ll;
ll  inf=0x3f3f3f3f3f;
struct node
{
    int v,w;
    node (int _v,int _w)
    {
        v=_v;
        w=_w;
    }
};
ll dis[MAX];
ll dis1[MAX];
vector<node>vec[MAX];
int n,m,f,s,t;
queue<int>que;
bool vis[MAX];

void spfa(int s)
{
    memset(vis,0,sizeof(vis));
    memset(dis,0x3f,sizeof(dis));

    dis[s]=0;
    que.push(s);
    vis[s]=1;

    while (!que.empty())
    {
       int frist=que.front();
       que.pop();
       vis[frist]=0;
       for(int i=0;i<(int)vec[frist].size();i++)
       {
           int v=vec[frist][i].v;
           if(dis[frist]+vec[frist][i].w<dis[v])
           {
               dis[v]=dis[frist]+(ll)vec[frist][i].w;

               if(vis[v]==0)
               {
                   que.push(v);
                   vis[v]=1;
               }

           }
       }
    }

}
void spfa1(int s)
{
    for(int i=0;i<n;i++)
        dis1[i]=dis[i];
    memset(vis,0,sizeof(vis));
    que.push(s);
    vis[s]=1;

    while (!que.empty())
    {
       int frist=que.front();
       que.pop();
       vis[frist]=0;
       for(int i=0;i<(int)vec[frist].size();i++)
       {
           int v=vec[frist][i].v;
           if(dis1[frist]+vec[frist][i].w<dis1[v])
           {
               dis1[v]=dis1[frist]+(ll)vec[frist][i].w;

               if(vis[v]==0)
               {
                   que.push(v);
                   vis[v]=1;
               }

           }
       }
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d%d%d%d%d",&n,&m,&f,&s,&t);
    for(int i=0;i<m;i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        vec[u].push_back(node(v,w));
        vec[v].push_back(node(u,w));
    }
    spfa(s);
    ll maxs=dis[t];
    for(int i=0;i<f;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        int mark=0;
        int j=0;
        for(int i=0;i<(int)vec[u].size();i++)
        {
            j++;
            if(vec[u][i].v==v)
            {
                //cout <<u<<" "<<v<<" "<<vec[u][i].w<<endl;
                mark=1;
                int w=vec[u][i].w;
                vec[u][i].w=0;
                spfa1(u);
              //  cout <<" "<<dis1[t]<<endl;
                if(dis1[t]<maxs)
                    maxs=dis1[t];
                vec[u][i].w=w;
            }

        }
        if(mark==0)
        {
            //cout <<u<<" "<<v<<" "<<inf<<endl;
            vec[u].push_back(node(v,inf));
            //for(int i=0;i<(int)vec[u].size();i++)
            //cout <<"u "<<u<<" "<<vec[u][i].v<<" "<<vec[u][i].w<<endl;
            ll w=vec[u][j].w;
            vec[u][j].w=0;
            //cout <<"g "<<vec[u][j].v<<" "<<vec[u][j+1].w<<endl;
            spfa1(u);
            // cout <<" "<<dis1[t]<<endl;
            if(dis1[t]<maxs)
              maxs=dis1[t];
            vec[u][j].w=w;
        }

    }

    //for(int i=0;i<n;i++)
    cout <<maxs<<endl;

    return 0;
}

3

描述

万圣节的晚上,小Hi和小Ho在吃过晚饭之后,来到了一个巨大的鬼屋!

鬼屋中一共有N个地点,分别编号为1..N,这N个地点之间互相有一些道路连通,两个地点之间可能有多条道路连通,但是并不存在一条两端都是同一个地点的道路。

不过这个鬼屋虽然很大,但是其中的道路并不算多,所以小Hi还是希望能够知道从入口到出口的最短距离是多少?

 

输入

每个测试点(输入文件)有且仅有一组测试数据。

在一组测试数据中:

第1行为4个整数N、M、S、T,分别表示鬼屋中地点的个数和道路的条数,入口(也是一个地点)的编号,出口(同样也是一个地点)的编号。

接下来的M行,每行描述一条道路:其中的第i行为三个整数u_i, v_i, length_i,表明在编号为u_i的地点和编号为v_i的地点之间有一条长度为length_i的道路。

对于100%的数据,满足N<=10^5,M<=10^6, 1 <= length_i <= 10^3, 1 <= S, T <= N, 且S不等于T。

对于100%的数据,满足小Hi和小Ho总是有办法从入口通过地图上标注出来的道路到达出口。

输出

对于每组测试数据,输出一个整数Ans,表示那么小Hi和小Ho为了走出鬼屋至少要走的路程。

Sample Input

5 10 3 5
1 2 997
2 3 505
3 4 118
4 5 54
3 5 480
3 4 796
5 2 794
2 5 146
5 4 604
2 5 63

Sample Output

172

 

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

struct node
{
    int to,cost;
    node (int _to=0,int _cost=0) {to=_to;cost=_cost;}
};

#define inf 1e9

vector<node>vec[100005];
int dis[100005];

int n,m;

int spfa(int s)
{
    int ok=1;
    int vis[100005];
    int cis[100005];
    queue<int>que;
    memset(vis,0,sizeof(vis));
    memset(cis,0,sizeof(cis));


    for(int i=1; i<=n; i++)
    {
        dis[i]=inf;
    }

    dis[s]=0;
    que.push(s);
    vis[s]=1;
    cis[s]++;

    while (!que.empty())
    {
        int k=que.front();
        que.pop(),vis[k]=0;

        for(int i=0; i<(int)vec[k].size(); i++)
        {
            int v=vec[k][i].to;
            if(dis[v]>dis[k]+vec[k][i].cost)
            {

                dis[v]=dis[k]+vec[k][i].cost;

                if(vis[v]==0)
                {
                    que.push(v);
                    vis[v]=1;
                    cis[v]++;

                    if(cis[v]>n)
                       return 0;
                }

            }

        }

    }

    return ok;
}

int main()
{
    int s,t;

    while (cin>>n>>m)
    {

    cin >>s>>t;
    for(int i=1; i<=n; i++)
        vec[i].clear();

    for(int i=1; i<=m; i++)
    {
        int a,b,c;

        cin >>a>>b>>c;

            vec[a].push_back(node(b,c));
            vec[b].push_back(node(a,c));

    }

    if(spfa(s)==1)
        cout <<dis[t]<<endl;
    else
        cout <<"存在负权回路"<<endl;

    }


    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值