2018 ACM-ICPC南京网络赛 Magical Girl Haze(分层最短路)

2018 ACM-ICPC南京网络赛 Magical Girl Haze

There are NN cities in the country, and MM directional roads from uu to v(1\le u, v\le n)v(1≤u,v≤n). 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(1≤T≤5), 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 10N≤100000,M≤200000,K≤10,
0 \le C_i \le 1e90≤Ci​≤1e9. 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

边去重+分层最短路
分层图最短路,就是在分层图上解决最短路问题。
一般解决方法是多开一维记录状态,多开的维度记录状态的种类数即为分层数。

基本模型:在图上,有k次机会可以直接通过一条边而不计算边权,问起点与终点之间的最短路径。
多一种情况松弛判断就行,其实和bfs思想相同

和这个题一模一样的飞行路线HYSBZ2763

code:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100005;
const int maxm = 200005;
const int INF = 0x3f3f3f3f;
typedef long long ll;
struct node{
    int u,v;
    ll w;
    bool operator < (const node &a)const{//给边进行排序用于去重边选较短的
        if(u == a.u && v == a.v) return w < a.w;
        else if(u == a.u) return v < a.v;
        return u < a.u;
    }   
}edge[maxm<<1];
struct Node{
    ll dis;
    int x,k;
    Node(){}
    Node(ll d,ll u, ll cnt):dis(d),x(u),k(cnt){}
    bool operator < (const Node &a)const{
        return dis > a.dis;
    }
};
int n,m,k,head[maxn],cnt;
int to[maxm<<1],nxt[maxm<<1];
ll val[maxm<<1];
bool vis[maxn][15];
ll dis[maxn][15],ans;

inline void addedge(int u,int v,int w){
    to[++cnt] = v;
    nxt[cnt] = head[u];
    val[cnt] = w;
    head[u] = cnt;
}

void dijkstra(){
    priority_queue<Node> q;
    memset(dis,INF,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[1][0] = 0;//起点未让任何变为0,到达起点距离为0
    q.push(Node(0,1,0));
    while(!q.empty()){
        Node tmp = q.top();
        q.pop();
        int x = tmp.x,lev = tmp.k;
        if(vis[x][lev]) continue;//如果已经从这个点当前状态出发松弛过了,就跳过防止死循环
        vis[x][lev] = 1;//标记已经从这个点当前状态出发松弛过了
        for(int i = head[x]; i; i = nxt[i]){//开始松弛能到达的点
            int u = to[i];//分两种情况
            if(dis[x][lev] + val[i] < dis[u][lev]){//在不使任何新的边为0的情况下的松弛,相当于普通dijk
                dis[u][lev] = dis[x][lev] + val[i];
                if(!vis[u][lev]) q.push(Node(dis[u][lev],u,lev));//如果这个点这种状态还没当过出发点松弛就入队
            }
            if(lev + 1 <= k && dis[x][lev] < dis[u][lev+1]){//如果是这条边为0,再进行松弛,然后同上判断是否入队
                dis[u][lev+1] = dis[x][lev];
                if(!vis[u][lev+1]) q.push(Node(dis[u][lev+1],u,lev+1));
            }
        }
    }
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        cnt = 0;
        ans = 1e18;
        memset(head,0,sizeof(head));
        scanf("%d%d%d",&n,&m,&k);
        for(int i = 1; i <= m; i++){
            scanf("%d%d%lld",&edge[i].u,&edge[i].v,&edge[i].w);
        }//先暂时存边,但不存图
        int preu = -1,prev = -1;
        sort(edge+1,edge+1+m);
        //边去重,边建图
        for(int i = 1; i <= m; i++){
            if(!(edge[i].u == preu && edge[i].v == prev)){
                addedge(edge[i].u,edge[i].v,edge[i].w);
                preu = edge[i].u;
                prev = edge[i].v;   
            }
        }
        dijkstra();
        for(int i = 0; i <= k; i++) ans = min(ans,dis[n][i]);
        printf("%lld\n",ans);
    }   
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值