CF449B Jzzhu and Cities

CF449B Jzzhu and Cities

题目链接

这道题是一道比较套路的最短路的题目。

首先,考虑一条铁路可以被取代当且仅当有另一条仅走公路的或者走不是这条铁路的路径小于等于这条铁路的长度。

我们发现,这个过程就是在更新最短路的过程,我们先把最短路的数组 \(dis[i]\) 初始化为到 \(i\) 最短的铁路的长度,并标记为 \(1\),如果没有就设为正无穷。

然后在进行 \(Dijkstra\) 的时候发现如果这条路可以被上面的合法情况更新,就标记为 \(0\)

然后答案就是铁路总数减去仍然被标记的铁路数。

不过需要注意的是需要在进行初始化的时候将 \(dis[i]\) 也压入优先队列,不过需要去一下重复的,只压入最优的,否则会 \(TLE\)

#include<bits/stdc++.h>
#define pii pair<ll,int>
#define mp make_pair
#define one first
#define two second
#define ll long long
const int N=1e5+100,M=1e6+100;
const ll INF=LLONG_MAX-INT_MAX;
using std::mp;
using std::min;
using std::sort;
using std::pair;
using std::vector;
using std::greater;
using std::priority_queue;
struct edge{
    int s,e;
    ll v;
    int net;
}ed[M];
int n,m,k,tot,ans;
int head[N];
ll dis[N];
bool mark[N];
priority_queue<pii,vector<pii>,greater<pii> >q;
inline void clear()
{
    for (int i=1;i<=n;i++)
    dis[i]=INF;
    return ;
}
inline void Dijkstra(int x)
{
    dis[x]=0;
    q.push(mp(dis[x],x));
    while (!q.empty())
    {
        pii now=q.top();
        q.pop();
        if (dis[now.two]!=now.one) continue;
        for (int i=head[now.two];i;i=ed[i].net)
        {
            if (dis[ed[i].e]>dis[ed[i].s]+ed[i].v)
            {
                mark[ed[i].e]=0;
                dis[ed[i].e]=dis[ed[i].s]+ed[i].v;
                q.push(mp(dis[ed[i].e],ed[i].e));
            }
            if (dis[ed[i].e]==dis[ed[i].s]+ed[i].v) mark[ed[i].e]=0;
        }
    }
    return ;
}
inline void add(int s,int e,ll v)
{
    ed[++tot]=(edge){s,e,v,head[s]};
    head[s]=tot;
    return ;
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for (int i=1;i<=m;i++)
    {
        int s,e;
        ll v;
        scanf("%d%d%lld",&s,&e,&v);
        add(s,e,v);add(e,s,v);
    }
    clear();
    for (int i=1;i<=k;i++)
    {
        int e;
        ll v;
        scanf("%d%lld",&e,&v);
        dis[e]=min(v,dis[e]);
        mark[e]=1;
    }
    for (int i=1;i<=n;i++)
    if (mark[i]) q.push(mp(dis[i],i));
    Dijkstra(1);
    for (int i=1;i<=n;i++)
    if (mark[i]) ans++;
    printf("%d\n",k-ans);
    return 0;
}

其实也可以使用 \(set\) 来建图来达到去除重边的目的。

#include<bits/stdc++.h>
#define pii pair<ll,int>
#define mp make_pair
#define one first
#define two second
#define ll long long
const int N=1e5+100,M=1e6+100;
const ll INF=LLONG_MAX-INT_MAX;
using std::mp;
using std::map;
using std::sort;
using std::pair;
using std::vector;
using std::greater;
using std::priority_queue;
int n,m,k,tot,ans;
int head[N];
ll dis[N];
bool mark[N];
map<int,int>ed[N];
priority_queue<pii,vector<pii>,greater<pii> >q;
inline ll min(ll x,ll y) {return x<y ? x:y;}
inline void clear()
{
    for (int i=1;i<=n;i++)
    dis[i]=INF;
    return ;
}
inline void Dijkstra(int x)
{
    dis[x]=0;
    q.push(mp(dis[x],x));
    while (!q.empty())
    {
        pii now=q.top();
        q.pop();
        if (dis[now.two]!=now.one) continue;
        for (map<int,int>::iterator it=ed[now.two].begin();it!=ed[now.two].end();it++)
        {
            int e=it->one,v=it->two;
            if (dis[e]>dis[now.two]+v)
            {
                mark[e]=0;
                dis[e]=dis[now.two]+v;
                q.push(mp(dis[e],e));
            }
            if (dis[e]==dis[now.two]+v) mark[e]=0;
        }
    }
    return ;
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for (int i=1;i<=m;i++)
    {
        int s,e,v;
        scanf("%d%d%d",&s,&e,&v);
        map<int,int>::iterator it=ed[s].find(e);
        if (it==ed[s].end()) ed[s].insert(mp(e,v));
        else it->two=min(it->two,v);
        it=ed[e].find(s);
        if (it==ed[e].end()) ed[e].insert(mp(s,v));
        else it->two=min(it->two,v);
    }
    clear();
    for (int i=1;i<=k;i++)
    {
        int e,v;
        scanf("%d%d",&e,&v);
        dis[e]=min(v,dis[e]);
        mark[e]=1;
        q.push(mp(dis[e],e));
    }
    Dijkstra(1);
    for (int i=1;i<=n;i++)
    if (mark[i]) ans++;
    printf("%d\n",k-ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/last-diary/p/11693846.html
今日推荐