题解 P2939 【[USACO09FEB]改造路Revamping Trails】

分层图+堆优化的题

分层图,顾名思义就是将图分层,每一层代表一个不同状态。如本题中的一层就代表修建一次高速公路(或说将一条路免费),连接每一层图的则是边权为0的单向边。

因为我们并不需要将修建高速公路的机会使用完,所以最终答案应从每一层的节点N中找。

为了不T掉,我们要用堆优化降低复杂度。

因此思路如下:

  • 根据题意建立k+1层,每层n个节点的分层图;
  • 堆优化DIJ遍历;
  • 在每一层的节点n中取最小值作为答案输出。

code:

#include<bits/stdc++.h>
using namespace std;
int n,m,k,s,t,w[100100],fst[100100],nex[100100],v[100100],dis[32][10100],a,b,c,tot,vis[32][10100];
struct item
{
    int lev,d,x;
    bool operator< (const item &x) const
    {
        return d>x.d;
    }
};
priority_queue<item>q;
void add(int a,int b,int c)
{
    nex[++tot]=fst[a];
    w[tot]=c;
    v[tot]=b;
    fst[a]=tot;
    return ;
}
void dij()
{
    dis[0][s]=0;
    q.push((item){0,0,s});
    while(!q.empty())
    {
        int x=q.top().x,d=q.top().d,lev=q.top().lev;
        //cout<<lev<<" "<<x<<" "<<d<<" "<<vis[lev][x]<<endl;
        //system("pause");
        q.pop();
        if(vis[lev][x])
        continue;
        vis[lev][x]=1;
        for(int i=fst[x];i!=-1;i=nex[i])
        {
            if(!vis[lev][v[i]]&&d+w[i]<dis[lev][v[i]])
            {
                dis[lev][v[i]]=d+w[i];
                q.push((item){lev,d+w[i],v[i]});
            }
            if(!vis[lev+1][v[i]]&&d<dis[lev+1][v[i]]&&lev+1<=k)
            {
                dis[lev+1][v[i]]=d;
                q.push((item){lev+1,d,v[i]});
            }
        }
    }
    return ;
}
int main()
{
    memset(fst,-1,sizeof(fst));
    memset(dis,0x7f/3,sizeof(dis));
    cin>>n>>m>>k;
    s=1;t=n;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
        add(b,a,c);
    }
    dij();
    int ans=1e8;
    for(int i=0;i<=k;i++)
    {
        ans=min(ans,dis[i][t]);
    }
    cout<<ans;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lost-in-tianyi/p/10725624.html