Codeforces Round #257 (Div. 2) D. Jzzhu and Cities

本文解析了CodeForces竞赛中一道关于最短路径的问题D题。通过Dijkstra算法求解在保持最短路径不变的前提下,最多能移除多少条铁路。文章详细介绍了算法实现过程及代码细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 题目链接:http://codeforces.com/contest/450/problem/D
  • 题意:给n个城市、m条公路、k条铁路(铁路只在1号城市与其他城市间)。算出在最短路不变的情况下,最多能去除多少条铁路
  • 算法:最短路 dijkstra
  • 思路:
    • 先把m个公路建图,这样边数达到2*m, 在对k 个铁路建图,进而可以判断边为公路还是铁路。当最短路是公路时,令flag=1; 当最短路为铁路时,令flag=0。当公路、铁路都最短时,令flag=0;
    • 遍历所有城市,当flag==1时说明连在这个点需要连一条铁路,并将剩余铁路去除;当flag==0时,说明这个点不需要铁路,并将这个点上所有铁路去除。
  • 坑点
    • 有些城市之间只有铁路,没有公路
    • dijkstra 松弛时只有dis[e.v] > dis[v] + e.w 时才会 对dis[e.v]赋值,使得无法在公路dis和铁路dis相等时进行标记,而需要另用一个if判断相等

#include <bits/stdc++.h>
#define pi acos(-1)
using namespace std;
typedef long long LL;
const LL INF = 0x3f3f3f3f;
const LL ll_INF = 0x3f3f3f3f3f3f3f3f;
const LL maxn = 300100;
const int mod = 1000000007;

typedef pair<LL, LL> P;
priority_queue<P,vector<P>,greater<P> > que;

struct Edge{ LL v, w, next; } es[3*maxn];
LL head[maxn];
LL tr[maxn];
LL flag[maxn];

LL n, m, u, v, w, s, t, cnt, dis[maxn];
void add(LL u, LL v, LL w)
{
    es[cnt].v = v;
    es[cnt].w = w;
    es[cnt].next = head[u];
    head[u] = cnt++;
}
void dijkstra()
{
    P p;
    Edge e;
    LL v;
    fill(dis, dis+maxn, ll_INF);
    memset(flag, 0, sizeof(flag));
    dis[s] = 0;
    que.push(P(0, s));
    while(!que.empty()){
        p = que.top(); que.pop();
        v = p.second;
        if(dis[v] < p.first)
            continue;
        for(LL i=head[v]; i!=-1LL; i=e.next){
            e = es[i];
            if(dis[e.v] > dis[v] + e.w){
                dis[e.v] = dis[v] + e.w;
                que.push(P(dis[e.v], e.v));
                if(i>=2*m) flag[e.v]=1;
                else flag[e.v]=0;
            }
            else if((dis[e.v] == dis[v] + e.w) && i<2*m ) flag[e.v]=0;
        }
    }
}
int main()
{
        LL k;
        scanf("%I64d%I64d%I64d", &n, &m, &k);
        cnt=0;
        memset(head, -1LL, sizeof(head));
        memset(tr, 0, sizeof(tr));
        for(LL i=0; i<m; i++){
            scanf("%I64d%I64d%I64d", &u, &v, &w);
            add(u, v, w);
            add(v, u, w);
        }
        s=1;
        LL a, b, ans=0;
        for(LL i=0; i<k; i++){
            scanf("%I64d%I64d", &a, &b);
            add(s, a, b);
            add(a, s, b);
            tr[a]++;
        }
        dijkstra();
        for(LL i=1; i<=n; i++){
            if(flag[i]==1) ans+=tr[i]-1;
            else ans+=tr[i];
        }
        printf("%I64d\n", ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值