cf954 Educational Round 40 Rated for Div2-D【最短路】

Date:2022.01.22
题意:n个点m条边,起点为s终点为t,求最多连上多少条边能使s->t的距离不变近。
在这里插入图片描述

思路:好简单的2d。两次Dijkstra,分别以 s s s t t t为起点,距离分别为 d i s t 1 [ ] 、 d i s t 2 [ ] dist1[]、dist2[] dist1[]dist2[]。之后 O ( n 2 ) O(n^2) O(n2)枚举任意两点,如果两点间有边则跳过;如果无边且加上这个边 < i , j > <i,j> <i,j>之后,如果 d i s t 1 [ i ] + d i s t 2 [ j ] + 1 dist1[i]+dist2[j]+1 dist1[i]+dist2[j]+1 ∣ ∣ || d i s t 1 [ j ] + d i s t 2 [ i ] + 1 dist1[j]+dist2[i]+1 dist1[j]+dist2[i]+1 < < < d i s t 1 [ t ] dist1[t] dist1[t],即若导致路径变短则不能选,否则能选。
除此之外,发现了个问题,堆优化Dijkstra里 p r i o r i t y q u e u e priority_queue priorityqueue中如果存 p a i r < > pair<> pair<>类型且分别为点编号 j j j和到 j j j点的最短距离 d i s t [ j ] dist[j] dist[j],则 d i s t [ j ] dist[j] dist[j]要在前, j j j要在后,才发现是因为 p r i o r i t y q u e u e priority_queue priorityqueue排序自动先按 p a i r < > pair<> pair<>里的 f i r s t first first从小到大排序,再按 s e c o n d second second 从小到大排序,放反了会错。
代码如下:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 2010;
typedef long long LL;
typedef pair<LL, LL> PII;
LL dist1[N],dist2[N],n,m,ss,tt,g[N][N];
LL h1[N],e1[N],ne1[N],w1[N],idx1;
LL h2[N],e2[N],ne2[N],w2[N],idx2;
bool st1[N],st2[N];
void add1(LL x,LL y,LL c)
{
    e1[idx1]=y;
    ne1[idx1]=h1[x];
    w1[idx1]=c;
    h1[x]=idx1++;
}
void add2(LL x,LL y,LL c)
{
    e2[idx2]=y;
    ne2[idx2]=h2[x];
    w2[idx2]=c;
    h2[x]=idx2++;
}
void dijkstra1()
{
    memset(dist1,0x3f,sizeof dist1);
    dist1[ss]=0;
    priority_queue<PII,vector<PII>,greater<PII> >heap;
    heap.push({0,ss});
    while(heap.size())
    {
        PII t=heap.top();heap.pop();
        LL id=t.second,dis=t.first;
        if(st1[id]) continue;
        st1[id]=true;
        for(int i=h1[id];i!=-1;i=ne1[i])
        {
            LL j=e1[i];
            if(dist1[j]>dis+w1[i])
            {
                dist1[j]=dis+w1[i];
                heap.push({dist1[j],j});
            }
        }
    }
}
void dijkstra2()
{
    memset(dist2,0x3f,sizeof dist2);
    dist2[tt]=0;
    priority_queue<PII,vector<PII>,greater<PII> >heap;
    heap.push({0,tt});
    while(heap.size())
    {
        PII t=heap.top();heap.pop();
        LL id=t.second,dis=t.first;
        if(st2[id]) continue;
        st2[id]=true;
        for(int i=h2[id];i!=-1;i=ne2[i])
        {
            LL j=e2[i];
            if(dist2[j]>dis+w2[i])
            {
                dist2[j]=dis+w2[i];
                heap.push({dist2[j],j});
            }
        }
    }
}
int main()
{
    memset(h1,-1,sizeof h1);
    memset(h2,-1,sizeof h2);
    cin>>n>>m>>ss>>tt;
    while (m -- )
    {
        LL x,y;cin>>x>>y;
        add1(x,y,1);add1(y,x,1);
        add2(x,y,1);add2(y,x,1);
        g[x][y]=g[y][x]=1;
    }
    dijkstra1();
    dijkstra2();
    LL ans=0;
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
        {
            if(g[i][j]) continue;
            if(1+dist1[i]+dist2[j]>=dist1[tt] && 1+dist1[j]+dist2[i]>=dist1[tt])
                ans++;
        }
    cout<<ans;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值