题解 P4568 【[JLOI2011]飞行路线】

P4568 [JLOI2011]飞行路线

分层图模板题,相似的题还有P4822 [BJWC2012]冻结,
P2939 [USACO09FEB]改造路Revamping Trails,其实做惯了也就不难了。。

为什么有这篇题解?

  • 感觉写的比较简洁清晰

  • 线段树优化最短路

一、堆优化dijkstra

652ms / 25.58MB / 1.31KB C++

#include
#include
#include
using namespace std;
const int MAXN=110005,MAXM=2500001;
struct edge {
    int to,dis,next;
} e[MAXM];
int n,m,k,s,t,head[MAXN],dis[MAXN],cnt;
bool vis[MAXN];
struct node {
    int dis,pos;
    bool operator <(const node &x)const {
        return x.dis q;
inline void add_edge(int u,int v,int d) {
    e[++cnt].dis=d;
    e[cnt].to=v;
    e[cnt].next=head[u];
    head[u]=cnt;
}
inline void dijkstra() {
    memset(dis,0x3f,sizeof(dis));
    dis[s]=0;
    q.push((node) {
        0,s
    });
    while(!q.empty()) {
        node tmp=q.top();
        q.pop();
        int x=tmp.pos,d=tmp.dis;
        if (vis[x]) continue;
        vis[x]=1;
        for (int i=head[x]; i; i=e[i].next) {
            int y=e[i].to;
            if (dis[y]>dis[x]+e[i].dis) {
                dis[y]=dis[x]+e[i].dis;
                if (!vis[y])
                    q.push((node) {
                    dis[y],y
                });
            }
        }
    }
}
int main() {
    scanf("%d%d%d%d%d",&n,&m,&k,&s,&t);
    for (register int i=0; i

二、线段树dijkstra

523ms / 26.64MB / 1.41KB C++

#include
#include
using namespace std;
const int N=110005,M=2500001;
int n,m,kth,cnt,s,t;
int tr[N<<2],h[N],nxt[M],to[M],w[M],dis[N];
#define R register int
inline int rd() {
    int t=0;
    char c=getchar();
    while(c<'0' || c>'9') c=getchar();
    while(c>='0' && c<='9') t=(t<<3)+(t<<1)+(c^48),c=getchar();
    return t;
}
inline void add_edge(int u,int v,int _w) {
    nxt[++cnt]=h[u],to[cnt]=v,w[cnt]=_w,h[u]=cnt;
}
#define min(a,b) (dis[a]>1;
    if (pos<=mid) modify(o<<1,l,mid,pos,val);
    else modify(o<<1|1,mid+1,r,pos,val);
    tr[o]=min(tr[o<<1],tr[o<<1|1]);
}
inline void dijkstra() {
    memset(dis,0x3f,sizeof(dis));
    dis[s]=0,modify(1,1,kth*n,s,s);//线段树存点的编号,然后通过比较dis上传
    for (R t=1,u,v; tdis[u]+w[i])
                dis[v]=dis[u]+w[i],modify(1,1,kth*n,v,v);
    }
}
int main() {
    n=rd(),m=rd(),kth=rd(),s=rd()+1,t=rd()+1;//编号加1,空出dis0的位置
    for (R i=1,u,v,_w; i<=m; i++) {
        u=rd()+1,v=rd()+1,_w=rd();
        add_edge(u,v,_w),add_edge(v,u,_w);
        for(int j=1; j<=kth; ++j) {
            add_edge(u+(j-1)*n,v+j*n,0);
            add_edge(v+(j-1)*n,u+j*n,0);
            add_edge(u+j*n,v+j*n,_w);
            add_edge(v+j*n,u+j*n,_w);
        }
    }
    for (R i=1;i<=kth;i++)
     add_edge(t+(i-1)*n,t+i*n,0);
    kth++;
    dijkstra();
    printf("%d",dis[(kth-1)*n+t]);
    return 0;
}

三、DP最短路

296ms / 2.26MB / 1.15KB C++

这种方法最快,而且数组的范围比较好确定

注意dis,vis,node是二维,要记录点的编号和所用次数

#include
#include
#include
using namespace std;
struct edge {
   int v,w,h;
} e[100010];
int n,m,K,s,t,cnt,ans,h[10010],d[10010][11];
bool vis[10010][11];
struct node {
   int u,k;
   bool operator <(const node &x) const {
       return d[u][k]>d[x.u][x.k];
   }
};
inline void add(int u,int v,int w) {
   e[++cnt]=(edge) {v,w,h[u]},h[u]=cnt;
}
inline void dijkstra() {
   priority_queue q;
   memset(d,0x3f,sizeof d);
   q.push((node) {
       s,0
   }),d[s][0]=0,vis[s][0]=1;//s点,用了0次
   while(!q.empty()) {
       node x=q.top();
       q.pop(),vis[x.u][x.k]=0;
       for (register int i=h[x.u],v,u,k; i; i=e[i].h) {
           if (d[v=e[i].v][k=x.k]>d[u=x.u][k]+e[i].w) {
               d[v][k]=d[u][k]+e[i].w;
               if (!vis[v][k]) q.push((node) {
                   v,k
               }),vis[v][k]=1;
           }//更新不使用的情况,k不变
           if (d[v][k+1]>d[u][k] && k

你可能感兴趣的:(题解 P4568 【[JLOI2011]飞行路线】)