ACM-ICPC 2018 南京赛区网络预赛 L. Magical Girl Haze (分层dijkstra)

本文介绍了一种利用分层图进行Dijkstra算法优化的方法,用于解决特定条件下从起点到终点的最短路径问题,特别是在有权限将路径上一定数量的边花费变为0的情况下。通过实例演示了算法的具体实现过程。

There are NN cities in the country, and MMdirectional roads from uu to v(1\le u, v\le n)v(1u,vn). Every road has a distance c_ici. Haze is a Magical Girl that lives in City 11, she can choose no more than KK roads and make their distances become 00. Now she wants to go to City NN, please help her calculate the minimum distance.

Input

The first line has one integer T(1 \le T\le 5)T(1T5), then following TT cases.

For each test case, the first line has three integers N, MN,M and KK.

Then the following MM lines each line has three integers, describe a road, U_i, V_i, C_iUi,Vi,Ci. There might be multiple edges between uu and vv.

It is guaranteed that N \le 100000, M \le 200000, K \le 10N100000,M200000,K10,
0 \le C_i \le 1e90Ci1e9. There is at least one path between City 11 and City NN.

Output

For each test case, print the minimum distance.

样例输入
1
5 6 1
1 2 2
1 3 4
2 4 3
3 4 1
3 5 6
4 5 2
样例输出
3

 

题目大意:

给你n个点编号从1到n,共有m条有向边,问从1到n的最短路,如果有权利使路径上的k条边的花费变为0。

 

分层图dijkstra。

令dis[i][j]为i点使路径上j条边的花费变为0的情况下的最小距离。这样在更新dis数表的时候,遇到一条边,可以考虑用或不用这条边。这样跑dijkstra就可以了。(感觉上建图直接分k+1层也可以)

dijkstra堆优化算法需要掌握。在边权为正值时,它比spfa速度更稳定(spfa速度会退化)。实际上,这道题就是卡spfa的。

 

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>

using namespace std;

const int maxn=100000;
const int maxm=200000;
const int inf=2000000000;

int to[maxm+10];
int w[maxm+10];
int nex[maxm+10];
int head[maxn+10];

int dis[maxn+10][11];
struct tnode
{
    int a,b;
    int dis;
    bool operator<(const tnode& y) const
    {
        return dis>y.dis;
    }
};

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        memset(head,-1,sizeof(head));
        for(int i=0,u,v,c;i<m;i++)
        {
            scanf("%d%d%d",&u,&v,&c);
            to[i]=v;w[i]=c;
            nex[i]=head[u];head[u]=i;
        }

        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<=k;j++)
                dis[i][j]=inf;
        }
        priority_queue<tnode> q;
        dis[1][0]=0;
        q.push((tnode){1,0,0});
        while(!q.empty())
        {
            tnode node=q.top();q.pop();
            int a=node.a,b=node.b,d=node.dis;
            if(d!=dis[a][b])   continue;
            for(int i=head[a];i!=-1;i=nex[i])
            {
                int u=a,v=to[i],c=w[i];
                if(dis[v][b]>dis[u][b]+c)
                {
                    dis[v][b]=dis[u][b]+c;
                    q.push((tnode){v,b,dis[v][b]});
                }
                if(b!=k&&dis[v][b+1]>dis[u][b])
                {
                    dis[v][b+1]=dis[u][b];
                    q.push((tnode){v,b+1,dis[v][b+1]});
                }
            }
        }

        int ans=inf;
        for(int i=0;i<=k;i++)
        {
            ans=min(ans,dis[n][i]);
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/acboyty/p/9652984.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值