Jzzhu and Cities CodeForces - 449B

本文介绍了一种使用Dijkstra算法解决特定问题的方法,通过优化算法流程实现高效寻找最短路径的目标。文中详细解释了如何结合铁路和公路网络的特点,利用标记和松弛技巧减少不必要的计算,最终得出最优解。

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

点击打开链接

做的很迷的一道题。。

开始用Dijkstra 将公路铁路都加入图中 看每一个有铁路直达的点 能否通过除这条直达铁路之外的路径来松弛 即该点是否存在代价小于等于这条铁路的路径

WA的很离谱 一时还找不到问题的原因 留坑。。也希望路过的大佬指正。。

 

 

 

#更正 填坑

 

 

其实没想的那么难 先记录下每个点通过走铁路直达的最短距离(dis2) 同时记录下从首都到这一点一共多少铁路(多条铁路肯定只留一条)

然后公路铁路都建边 跑dijkstra (这里建边时要区分是公路还是铁路)  距离记为dis1

在松弛过程中先判断是公路还是铁路 如果是一条铁路(堆顶元素代表的顶点u是1 与遍历到的点v有一条铁路直达) 那就只需要看u能不能松弛v 这是为了之后松弛其他点 因为如果这条铁路不需要去掉 那他就可能松弛其他点 不能忽略他的作用

 

 

如果是一条公路 先通过 if(dis2[v]>=dis1[u]+w) flag[v]=1; 判断是否可以把1到v的铁路去掉 可以的话就把v标记一下(flag[v]=1) 然后再正常松弛

最后扫一遍所有点 如果该点有铁路 看该点的这些铁路是否都没有用 (即可以不走直达该点的任何铁路 通过其他公路和铁路得到更短距离) 都没用则去掉所有 否则只保留一条 那一条最短铁路

 
#include <bits/stdc++.h>
using namespace std;
#define ll long long

struct node1
{
    int v;
    ll w;
    int t;
    int next;
};

struct node2
{
    bool friend operator < (node2 n1,node2 n2)
    {
        return n1.val>n2.val;
    }
    int id;
    ll val;
};

node1 edge[700010];
priority_queue <node2> que;
ll dis1[100010],dis2[100010];
int first[100010],book[100010],flag[100010],cnt[100010];
int n,m1,m2,num;

void addedge(int u,int v,ll w,int t)
{
    edge[num].v=v;
    edge[num].w=w;
    edge[num].t=t;
    edge[num].next=first[u];
    first[u]=num++;
    return;
}

void dijkstra()
{
    node2 cur,tem;
    ll w;
    int i,u,v,t,sum;
    while(!que.empty()) que.pop();
    memset(dis1,0x3f,sizeof(dis1));
    memset(book,0,sizeof(book));
    memset(flag,0,sizeof(flag));
    tem.id=1,tem.val=0;
    que.push(tem);
    dis1[1]=0;
    while(!que.empty())
    {
        cur=que.top();
        que.pop();
        u=cur.id;
        if(book[u]) continue;
        book[u]=1;
        for(i=first[u];i!=-1;i=edge[i].next)
        {
            v=edge[i].v,w=edge[i].w,t=edge[i].t;
            if(t==0)
            {
                if(dis2[v]>=dis1[u]+w) flag[v]=1;
                if(dis1[v]>dis1[u]+w)
                {
                    dis1[v]=dis1[u]+w;
                    tem.id=v,tem.val=dis1[v];
                    que.push(tem);
                }
            }
            else
            {
                if(dis1[v]>dis1[u]+w)
                {
                    dis1[v]=dis1[u]+w;
                    tem.id=v,tem.val=dis1[v];
                    que.push(tem);
                }
            }
        }
    }
    sum=0;
    for(i=1;i<=n;i++)
    {
        if(flag[i])
        {
            sum+=cnt[i];
        }
        else if(cnt[i]!=0)
        {
            sum+=(cnt[i]-1);
        }
    }
    printf("%d\n",sum);
    return;
}

int main()
{
    ll w;
    int i,u,v;
    while(scanf("%d%d%d",&n,&m1,&m2)!=EOF)
    {
        memset(first,-1,sizeof(first));
        num=0;
        for(i=1;i<=m1;i++)
        {
            scanf("%d%d%lld",&u,&v,&w);
            addedge(u,v,w,0);
            addedge(v,u,w,0);
        }
        memset(dis2,0x3f,sizeof(dis2));
        memset(cnt,0,sizeof(cnt));
        for(i=1;i<=m2;i++)
        {
            scanf("%d%lld",&v,&w);
            addedge(1,v,w,1);
            dis2[v]=min(dis2[v],w);
            cnt[v]++;
        }
        dijkstra();

    }
    return 0;
}

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值