计蒜客 31001

题目链接:https://nanti.jisuanke.com/t/31001

题意:

一带权有向图,有 n 个节点编号1~n,m条有向边,现在一人从节点 1 出发,他有最多 k 次机会施展魔法使得某一条边的权变成 0,问他走到节点 n 的最小权值为多少。

题解:

将dist数组和vis数组都扩展一维:

dist[c][i]代表:已经使用了 c 次变0魔法后,走到节点 i 的最短距离;

vis[c][i]代表:已经使用了 c 次变0魔法后,走到节点 i 的最短距离,这个最短距离是否已经被准确计算完毕。

然后就是稍微改动一下原来的优先队列优化Dijkstra即可。

AC代码:

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

const int maxn=1e5+10;
const int maxm=2e5+10;
const int maxk=13;
const ll INF=0x3f3f3f3f3f3f3f3f;

int n,m,k;

struct Edge{
    int u,v;
    ll w;
    Edge(int u=0,int v=0,ll w=0){this->u=u,this->v=v,this->w=w;}
};
vector<Edge> E;
vector<int> G[maxn];
void init(int l,int r)
{
    E.clear();
    for(int i=l;i<=r;i++) G[i].clear();
}
void addedge(int u,int v,ll w)
{
    E.push_back(Edge(u,v,w));
    G[u].push_back(E.size()-1);
}

struct Qnode{
    int vertex;
    ll dist;
    int cnt;
    Qnode(int v=0,ll d=0,int c=0){this->vertex=v,this->dist=d,this->cnt=c;}
    bool operator <(const Qnode &oth)const{
        return dist>oth.dist;
    }
    //优先队列默认是降序排列,如果本节点小于另一个节点的意义是 本节点dist < 另一个节点dist,
    //则优先队列的队首放的就是最大的节点,就是dist最大的节点,显然我们要的是相反的情况,
    //所以设置本节点小于另一个节点的意义是 本节点dist > 另一个节点dist 即可。
};

ll dist[maxk][maxn];
bool vis[maxk][maxn];
void dijkstra(int s)
{
    for(int i=1;i<=n;i++)
    {
        for(int c=0;c<=k;c++)
        {
            dist[c][i]=((i==s)?0:INF);
            vis[c][i]=0;
        }
    }

    priority_queue<Qnode> Q;
    Q.push(Qnode(s,0,0));
    while(!Q.empty())
    {
        int u=Q.top().vertex, c=Q.top().cnt; Q.pop();
        if(vis[c][u]) continue;
        vis[c][u]=1;
        for(int i=0;i<G[u].size();i++)
        {
            Edge &e=E[G[u][i]]; int v=e.v;
            if(!vis[c][v] && dist[c][v]>dist[c][u]+e.w)
            {
                dist[c][v]=dist[c][u]+e.w;
                Q.push(Qnode(v,dist[c][v],c));
            }
            if(c+1<=k && !vis[c+1][v] && dist[c+1][v]>dist[c][u])
            {
                dist[c+1][v]=dist[c][u];
                Q.push(Qnode(v,dist[c+1][v],c+1));
            }
        }
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&k);
        init(1,n);
        for(int i=1;i<=m;i++)
        {
            int u,v; ll w;
            scanf("%d%d%lld",&u,&v,&w);
            addedge(u,v,w);
        }
        dijkstra(1);
        ll ans=INF;
        for(int c=0;c<=k;c++) ans=min(ans,dist[c][n]);
        printf("%lld
",ans);
    }
}
原文地址:https://www.cnblogs.com/dilthey/p/9594990.html