1. 程式人生 > >L——Magical Girl Haze 【Dijkstra演算法+分層圖思想】

L——Magical Girl Haze 【Dijkstra演算法+分層圖思想】

  • 1000ms
  • 262144K

description:
There are N cities in the country, and M directional roads from u to v(1≤u,v≤n). Every road has a distance ci​. Haze is a Magical Girl that lives in City 1, she can choose no more than K roads and make their distances become 0. Now she wants to go to City N, please help her calculate the minimum distance.

Input
The first line has one integer T(1≤T≤5), then following T cases.

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

Then the following M lines each line has three integers, describe a road, Ui​,Vi​,Ci​. There might be multiple edges between u and v.

It is guaranteed that N≤100000,M≤200000,K≤10,
0 ≤Ci​≤1e9. There is at least one path between City 1 and City N.

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

題解思路:迪傑斯特拉最短路+dp分層圖思想,將距離陣列設定為dist[maxn][11],則dist[i][j]表示從起點開始到i節點,途中將j條路徑免費的最短路距離。分層圖又是什麼意思呢?以免費路徑相同的為一層,這樣在鬆弛時可以選擇是否讓當前的邊變為0,程式碼如下:
1.選擇這條邊不為0

if(d[e.to][lev]>d[u
][lev]+e.dist) { d[e.to][lev]=d[u][lev]+e.dist; Q.push(HeapNode(d[e.to][lev],lev*(n+1)+e.to)); }

2.選擇這條邊為0,進入下一層,,則dist[e.to][lev]變為dist[e.to][lev+1]因為多讓一條邊變為0

if(d[e.to][lev+1]>d[u][lev])
{
     d[e.to][lev+1]=d[u][lev];
     Q.push(HeapNode(d[e.to][lev+1],(lev+1)*(n+1)+e.to));
}

這樣,全部程式碼就寫出來了。
ps:分層圖還是第一次碰到,圖上dp也不會做,還得好好補補。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

typedef long long ll;

const int maxn=100003;
const int INF=0x3f3f3f3f;

struct HeapNode
{
    ll d;
    int u;
    HeapNode(ll _d=0,int _u=0):d(_d),u(_u){}
    bool operator <(const HeapNode &rhs)const
    {
        return d>rhs.d;
    }
};

struct Edge
{
    int from;
    int to;
    ll dist;
    Edge(int u=0,int v=0,ll dist=0):from(u),to(v),dist(dist){}
};

vector<Edge>edges;

vector<int>G[maxn];

void add_edges(int from,int to,ll dist)
{
    edges.push_back(Edge(from,to,dist));
    int m=edges.size();
    G[from].push_back(m-1);
}

void init(int n)
{
    for(int i=0;i<n;i++)
    {
        G[i].clear();
    }
    edges.clear();
}

int n,m,k;
bool vis[maxn][11];//永久標記
ll d[maxn][11];//dp距離陣列,層次圖

void dijkstra(int s,int n,int k)
{
    memset(vis,false,sizeof(vis));
    priority_queue<HeapNode>Q;
    memset(d,INF,sizeof(d));
    Q.push(HeapNode(0,s));
    //vis[s][0]=true;
    d[s][0]=0;
    while(!Q.empty())
    {
        HeapNode x=Q.top();Q.pop();
        int lev=x.u/(n+1);//表示使Z條邊的長度為0
        int u=x.u%(n+1);
        if(vis[u][lev])continue;
        vis[u][lev]=true;
        for(int i=0;i<G[u].size();i++)
        {
            Edge &e=edges[G[u][i]];
            if(vis[e.to][lev])continue;
            //選擇1:不讓這條邊為0
            if(d[e.to][lev]>d[u][lev]+e.dist)
            {
                d[e.to][lev]=d[u][lev]+e.dist;
                Q.push(HeapNode(d[e.to][lev],lev*(n+1)+e.to));
            }
            if(lev==k)continue;
            //選擇2:讓這條邊為0,則dist[e.to][lev]變為dist[e.to][lev+1]因為多讓一條邊變為0
            if(d[e.to][lev+1]>d[u][lev])
            {
                d[e.to][lev+1]=d[u][lev];
                Q.push(HeapNode(d[e.to][lev+1],(lev+1)*(n+1)+e.to));
            }
        }
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int u,v;
        ll cost;
        scanf("%d%d%d",&n,&m,&k);
        init(n);
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%lld",&u,&v,&cost);
            add_edges(u,v,cost);
        }
        dijkstra(1,n,k);
        printf("%lld\n",d[n][k]);
    }
    return 0;
}