bzoj 2750: [HAOI2012]Road

本文介绍了一种基于最短路径算法的优化方案,用于评估单向道路网络中每条道路的重要性。通过枚举起点并使用SPFA算法计算最短路径,结合动态规划思想统计路径数量,实现了对网络中所有道路重要性的高效评估。

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

题意

C国有n座城市,城市之间通过m条单向道路连接。一条路径被称为最短路,当且仅当不存在从它的起点到终点的另外一条路径总长度比它小。两条最短路不同,当且仅当它们包含的道路序列不同。我们需要对每条道路的重要性进行评估,评估方式为计算有多少条不同的最短路经过该道路。现在,这个任务交给了你。n≤1500、m≤5000、w≤10000

题解

这题其实很简单
然后不知道为什么,耗了我一个中午。。
看来思维确实要康复一下了。。
考虑到n很小,你不妨可以枚举起点,然后暴力跑一次最短路
建一个最短路径图
然后对于一个点,他所可以增加的道路就是
(x)(y)
CODE:

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
typedef long long LL;
const LL MOD=1000000007;
const LL N=5005;
LL n,m;
struct qq
{
    LL x,y,z;
    LL last;
}e[N];LL num,last[N];
qq E[N];LL Num,Last[N];//最短路径图 
void init (LL x,LL y,LL z)
{
    num++;
    e[num].x=x;e[num].y=y;e[num].z=z;
    e[num].last=last[x];
    last[x]=num;
}
LL d[N];
void Init (LL x,LL y)
{
    Num++;d[y]++;
    E[Num].x=x;E[Num].y=y;
    E[Num].last=Last[x];
    Last[x]=Num;
}
LL f[N];
bool vis[N];
LL g[2][N];//起点开始有多少个点可以到他  它可以到多少个点 
void Get (LL X)
{
    queue<int> q;
    for (LL u=1;u<=n;u++)   
        if (d[u]==0)
            q.push(u);
    while (!q.empty())
    {
        LL x=q.front();q.pop();
        for (LL u=Last[x];u!=-1;u=E[u].last)
        {
            LL y=E[u].y;
            g[X][y]=g[X][y]+g[X][x];
            d[y]--;
            if (d[y]==0)    q.push(y);
        }
    }
}
LL ans[N];
void SPFA (LL x)
{
    memset(vis,false,sizeof(vis));
    memset(f,127,sizeof(f));
    queue<int> q;
    q.push(x);f[x]=0;vis[x]=true;
    while (!q.empty())
    {
        LL x=q.front();q.pop();
        for (LL u=last[x];u!=-1;u=e[u].last)
        {
            LL y=e[u].y;
            if (f[y]>f[x]+e[u].z)
            {
                f[y]=f[x]+e[u].z;
                if (vis[y]==false)
                {
                    vis[y]=true;
                    q.push(y);
                }
            }
        }
        vis[x]=false;
    }
    memset(d,0,sizeof(d));
    Num=0;memset(Last,-1,sizeof(Last));
    for (LL u=1;u<=num;u++)
    {
        LL x=e[u].x,y=e[u].y;
        if (f[y]==f[x]+e[u].z)
            Init(x,y);
    }
    for (LL u=1;u<=n;u++) g[0][u]=0;g[0][x]=1;
    Get(0);
    memset(d,0,sizeof(d));
    Num=0;memset(Last,-1,sizeof(Last));
    for (LL u=1;u<=num;u++)
    {
        LL x=e[u].x,y=e[u].y;
        if (f[y]==f[x]+e[u].z)
            Init(y,x);
    }
    for (LL u=1;u<=n;u++) g[1][u]=1;
    Get(1);
    for (LL u=1;u<=num;u++)
    {
        LL x=e[u].x,y=e[u].y;
        if (f[y]==f[x]+e[u].z)//如果是的话
            ans[u]=(ans[u]+g[0][x]*g[1][y]%MOD)%MOD;
    }
}
int main()
{
    num=0;memset(last,-1,sizeof(last));
    scanf("%lld%lld",&n,&m);
    for (LL u=1;u<=m;u++)
    {
        LL x,y,z;
        scanf("%lld%lld%lld",&x,&y,&z);
        init(x,y,z);
    }
    for (LL u=1;u<=n;u++)//枚举一个起点
        SPFA(u); 
    for (LL u=1;u<=m;u++)   printf("%lld\n",ans[u]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值