Gym 100812G Short Path

Gym 100812G Short Path

最短路问题 多源最短路

传送门:CodeForce

传送门:HustOJ

题意

无向图,点有0/1之分。找出距离最近的一对1。输出距离与点对。


思路

分析:
SPFA变形,单源最短路转化为,所有点到某个1之间的最短路,然后枚举中间边,找合法解。
解法:
SPFA,将所有1点同时初始化为0,同时进栈进行松弛,最终可求出每一点到最近的1的距离及最近的1是哪个点。然后遍历所有边,若一条边两边都是1,则路径合法;若两边都是0,且两边最近的1不同点,则路径合法;若一边0一边1,且两边最近的1不同点,则路径合法。最后将所有合法路径取最小值即为答案。

  • 首先,spfa求的是某一点到其他所有点的最短路,最开始初始化队列时将源点放入队列。如果开始时放多个源点进队列,那么算法求出的是其他所有点到任意一个源点的最短距离。
  • 所以我们把所有的1都放到队列里,求出的就是每一个0点到其最近的1的距离,顺带可以求出最近的1是谁。(对于一个1点,他最近的1就是本身)
  • 然后枚举边,如果一条边两侧的1点号是不同的,那么这条路径,记录路径长度与两端点。取最小的即可。

代码

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#define _ ios_base::sync_with_stdio(0);cin.tie(0);
#define M(a,b) memset(a,b,sizeof(a));
using namespace std;

const int MAXN=100005;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
int a[MAXN];
struct Edge
{
    int to, cost;
    Edge(){}
    Edge(int _a, int _b) { to=_a;cost=_b; }
};
vector<Edge> G[MAXN];
int pre[MAXN];
LL dis[MAXN];
int vis[MAXN];
void spfa(int n,int m)
{
    M(dis, 0x3f);M(pre, -1);M(vis, 0);
    queue<int> que;
    for(int i=1;i<=n;i++)
        if(a[i])
        {
            dis[i]=0;pre[i]=i;vis[i]=1;
            que.push(i);
        }
    while(!que.empty())
    {
        int temp=que.front();que.pop();vis[temp]=0;
        for(Edge u : G[temp])
        {
            int tt=u.to;int cc=u.cost;
            if(dis[tt]>dis[temp]+cc)
            {
                pre[tt]=pre[temp];dis[tt]=dis[temp]+cc;
                if(vis[tt]==0) { que.push(tt);vis[tt]=1; }
            }
        }
    }
}
int main()
{
    _
    int n;
    while(cin>>n)
    {
        int m;cin>>m;
        M(a, -1);
        for(int i=1;i<=n;i++) cin>>a[i];
        for(int i=0;i<m;i++)
        {
            int ta, tb, tc;cin>>ta>>tb>>tc;
            G[ta].push_back(Edge(tb, tc));
            G[tb].push_back(Edge(ta, tc));
        }
        spfa(n, m);
        LL d=loo;int f, t;
        for(int i=1;i<=n;i++)
        {
            for(Edge u : G[i])
            {
                int tt=u.to;int cc=u.cost;
                if(pre[tt]!=pre[i])
                {
                    if(d>dis[tt]+dis[i]+cc)
                    {
                        d=dis[tt]+dis[i]+cc;
                        f=pre[tt], t=pre[i];
                    }
                }
            }
        }
        if(d>=loo) cout<<"No luck at all"<<endl;
        else
        {
            cout<<d<<endl;
            cout<<f<<' '<<t<<endl;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值