[USACO09FEB] 改造路Revamping Trails | [JLOI2011] 飞行路线

题目链接:

改造路

飞行路线

其实这两道题基本上是一样的,就是分层图的套路题。

为什么是分层图呢?首先,我们的选择次数比较少,可以把这几层的图建出来而不会爆空间。然后因为选择一个边权为0的路线之后我们就进入了下一个状态,最短路的计算就和不选择这个边权为0的路线完全独立了。

所以我们把每一层的图建出来,相邻图有边的话连0边,其他的按照原样连。dis数组存最短路。\(最后答案就是dis[n*k+end]\),end为终点。

所以所以。。。也没有什么可说的???

注意要写dij,以后图论的题能不写spfa就别写。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#define MAXM 4100000
#define MAXN 410000
using namespace std;
bool done[MAXN];
int n,m,edge_number,st,end,k;
int dis[MAXN],head[MAXN];
struct Edge{int nxt,to,dis;}edge[MAXM];
struct Node{
    int u,d;
    friend bool operator <(struct Node x,struct Node y)
    {
        return x.d>y.d;
    }
};
void add(int from,int to,int dis)
{
    edge[++edge_number].dis=dis;
    edge[edge_number].to=to;
    edge[edge_number].nxt=head[from];
    head[from]=edge_number;
}
inline void dij()
{
    priority_queue<Node>q;
    memset(dis,0x3f,sizeof(dis));
    q.push((Node){st,0});
    dis[st]=0;
    while(!q.empty())
    {
        int u=q.top().u;
        q.pop();
        if(done[u]) continue;
        done[u]=1;
        for(int i=head[u];i;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(dis[v]>dis[u]+edge[i].dis)
            {
                dis[v]=dis[u]+edge[i].dis;
                q.push((Node){v,dis[v]});
            }
        }
    }
}
int main()
{

    scanf("%d%d%d",&n,&m,&k);
    st=1,end=n;
    for(int i=1;i<=m;i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
        add(v,u,w);
        for(int j=1;j<=k;j++)
        {
            add(u+(j-1)*n,v+j*n,0);
            add(v+(j-1)*n,u+j*n,0);
            add(u+j*n,v+j*n,w);
            add(v+j*n,u+j*n,w);
        }
    }
    for(int i=1;i<=k;i++)
        add((i-1)*n+end,i*n+end,0);
    dij();
    printf("%d\n",dis[n*k+end]);
    return 0;
}
posted @ 2018-10-29 15:26  风浔凌  阅读(225)  评论(0编辑  收藏  举报