zoukankan      html  css  js  c++  java
  • P3831 [SHOI2012]回家的路

    P3831 [SHOI2012]回家的路

    分层图基础题,就是建图稍有麻烦


    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<map>
    #include<iomanip>
    #include<cstring>
    #define reg register
    #define EN std::puts("")
    #define LL long long
    inline int read(){
    	register int x=0;register int y=1;
    	register char c=std::getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
    	return y?x:-x;
    }
    //P3831 [SHOI2012]回家的路 https://www.luogu.com.cn/problem/P3831
    //一个网格,只能沿一个方向(横或纵)走
    //某些交叉点可以改变方向
    //沿一个方向走的时候,走一格花费两个时间,改变一次方向花费一个时间 
    //给出这些点,问网格中两点之间最短时间
    
    //分层图,为每个可以改变方向的点(按照题目背景是换乘点),分别创建两个虚拟节点
    //一个是横着走的,也就是走到这里只能继续横着走
    //一个是纵列方向走
    //然后,对于每一横行,依次从左往右把这些在一行的点连边
    //纵列也是如此 
    //然后每一个换乘点,横纵方向的两个点之间连一个时间为 1 的点,表示换成
    
    //起点和终点也看作换乘点,这样方便我们连边
    //只不过它们的横纵方向的两点间边权为 0 ,因为在起点并不存在换乘的问题 
     
    //1-m 是横列换乘点的编号
    //m+1 是起点的横列 
    //m+2 是终点的横列 
    //m+3-2*m+2 是纵列换乘点的编号
    //2*m+3 起点纵列
    //2*m+4 终点纵列
    //1-m 分别和 m+2-2*m+2 连权值为 1 的边
    //m+1 和 2*m+3 以及 m+2 和 2*m+4 连权值为 0 的边 
    //以 m+1 或 2*m+3 任意一个为虚构的图中的起点 
    //以 m+2 或 2*m+4 任意一个为虚构的图中的终点 
    //设横列编号为 id 则对应的纵列编号为 id+m+2
    
    //数组尽量开大,一开始算错 WA 了 
    struct data{
    	int x,y,id;
    }a[100009];
    int dis[200009],in[200009];
    int fir[200009],nex[700006],to[700006],w[700006],tot;
    int heap[200009],size; 
    inline int cmpx(data aa,data aaa){return aa.x==aaa.x?aa.y<aaa.y:aa.x<aaa.x;}
    inline int cmpy(data aa,data aaa){return aa.y==aaa.y?aa.x<aaa.x:aa.y<aaa.y;}
    inline void add(int u,int v,int len){
    	to[++tot]=v;w[tot]=len;
    	nex[tot]=fir[u];fir[u]=tot;
    }
    inline void link(int u,int v,int len){
    	add(u,v,len);add(v,u,len);
    }
    inline void push(int x){
    	heap[++size]=x;
    	reg int i=size,fa;
    	while(i>1){
    		fa=i>>1;
    		if(dis[heap[fa]]<=dis[heap[i]]) return;
    		std::swap(heap[fa],heap[i]);i=fa;
    	}
    }
    inline int pop(){
    	int ret=heap[1];heap[1]=heap[size--];
    	int i=1,ls,rs;
    	while((i<<1)<=size){
    		ls=i<<1;rs=ls|1;
    		if(rs<=size&&dis[heap[rs]]<dis[heap[ls]]) ls=rs;
    		if(dis[heap[ls]]>=dis[heap[i]]) break;
    		std::swap(heap[i],heap[ls]);i=ls;
    	}
    	return ret;
    }
    inline void dij(int start){
    	std::memset(dis,0x3f,sizeof dis);dis[start]=0;
    	push(start);in[start]=1;
    	while(size){
    		reg int u=pop(),v;in[u]=0;
    		for(reg int i=fir[u];i;i=nex[i]){
    			v=to[i];
    			if(dis[v]>dis[u]+w[i]){
    				dis[v]=dis[u]+w[i];
    				if(!in[v]) push(v),in[v]=1;
    			}
    		}
    	}
    }
    inline void build(int m){
    	std::sort(a+1,a+1+m+2,cmpx);
    	for(reg int i=1;i<=m+2;){
    		int now_x=a[i].x;
    		for(i++;i<=m+2&&a[i].x==now_x;i++) link(a[i].id,a[i-1].id,(a[i].y-a[i-1].y)<<1);
    	}
    	std::sort(a+1,a+1+m+2,cmpy);
    	for(reg int i=1;i<=m+2;){
    		int now_y=a[i].y;
    		for(i++;i<=m+2&&a[i].y==now_y;i++) link(a[i].id+m+2,a[i-1].id+m+2,(a[i].x-a[i-1].x)<<1);
    	}
    	for(reg int i=1;i<=m;i++) link(i,i+m+2,1);
    	link(m+1,2*m+3,0);link(m+2,2*m+4,0);
    }
    int main(){
    	read();int m=read();
    	for(reg int i=1;i<=m+2;i++) a[i].x=read(),a[i].y=read(),a[i].id=i;
    	build(m);
    	dij(m+1);
    	std::printf("%d",dis[2*m+4]==0x3f3f3f3f?-1:dis[2*m+4]);
    //		EN;EN;
    //		for(reg int i=1;i<=m*2+4;i++){
    //			std::printf("%d :  ",i);
    //			for(reg int j=fir[i];j;j=nex[j]) std::printf("%d ",to[j]);
    //			EN;
    //		}
    	return 0;
    }
    
  • 相关阅读:
    IIS7用进程池的PID查找占用CPU的站点
    CSS中属性的书写顺序
    int[] 和 string[] 互换
    csv 文件的读取
    扩展 DataGridView 的功能(三)
    [音乐] the dream catcher
    雷人的面试
    将MP3文件嵌入到exe中并播放
    扩展 DataGridView 的功能(二)
    扩展DataGridView 的功能(四)
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/12691317.html
Copyright © 2011-2022 走看看