洛谷 P3036 [USACO16DEC]Lasers and Mirrors激光和镜子

题目链接

以下内容引用自_Yunluo_ 的博客,原文链接

每个点拆成4个

img

蓝色虚线的边长度为0,橙色实线的边长度为1

然后再在节点中连边,像下图那样

img

最后建一个超级起点和超级终点,超级起点向原起点的四个节点连边(dis=0),原终点的四个节点向超级中电加边(dis=0)

跑最短路

各组节点之间连变的时候,可以分别按照x和y排序后加变

以样例为例:

img

引用结束

[Code]

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

int read(){
	int x=0; char c=getchar(); int flag=1;
	while(!isdigit(c)) { if(c=='-') flag=-1; c=getchar(); }
	while(isdigit(c)) { x=((x+(x<<2))<<1)+(c^48); c=getchar(); }
	return x*flag;
}

const int N=1e6+10;

int n;

struct Node{
    int x,y;
    int id;
}a[N];
bool cmp1(Node a,Node b) { if(a.x==b.x) return a.y<b.y; return a.x<b.x; }
bool cmp2(Node a,Node b) { if(a.y==b.y) return a.x<b.x; return a.y<b.y; }

struct Edge{
    int to,next,v;
}edge[N<<4];
int head[N<<2];
int tmp=0;

void add(int x,int y,int z){
    ++tmp;
    edge[tmp].to=y; edge[tmp].next=head[x]; edge[tmp].v=z;
    head[x]=tmp;
}

void Add_edge(int x,int y,int z){
    add(x,y,z); add(y,x,z);
}

int dep[N];

signed main(){
	memset(head,-1,sizeof(head));
    n=read();
    a[0].x=read(); a[0].y=read(); a[0].id=0;
    a[n+1].x=read(); a[n+1].y=read(); a[n+1].id=n+1;//存入汇点,源点
    for(int i=1;i<=n;i++){
	    a[i].x=read();a[i].y=read();a[i].id=i;
	}
	
	sort(a,a+n+2,cmp1);//按照x坐标排序
	
	for(int i=0;i<=n;i++){//在x坐标相同的之间连边
	    if(a[i].x==a[i+1].x){
		    Add_edge((a[i].id<<2)+3,(a[i+1].id<<2)+2,0);
		}
	}
	
	sort(a,a+n+2,cmp2); //按照y坐标排序
	
	for(int i=0;i<=n;i++){//在y坐标相同的之间连边
	    if(a[i].y==a[i+1].y){
		    Add_edge((a[i].id<<2)+4,(a[i+1].id<<2)+1,0);
		}
	}
	
	for(int i=0;i<=n;i++){//在拆点的四个点之间连边
	    Add_edge((a[i].id<<2)+1,(a[i].id<<2)+2,1);
	    Add_edge((a[i].id<<2)+1,(a[i].id<<2)+3,1);
	    Add_edge((a[i].id<<2)+1,(a[i].id<<2)+4,0);
	    Add_edge((a[i].id<<2)+2,(a[i].id<<2)+3,0);
	    Add_edge((a[i].id<<2)+2,(a[i].id<<2)+4,1);
	    Add_edge((a[i].id<<2)+3,(a[i].id<<2)+4,1);
	}
	
    memset(dep,-1,sizeof(dep));
	queue<int> q;
	dep[1]=dep[2]=dep[3]=dep[4]=0;
	q.push(1); q.push(2); q.push(3); q.push(4);//跑最短路,实际上应该是0/1 bfs
	
	while(!q.empty()){
	    int f=q.front(); q.pop();
	    for(int i=head[f];i!=-1;i=edge[i].next){
		    int t=edge[i].to;
		    if(dep[t]!=-1) continue;
		    dep[t]=dep[f]+edge[i].v;
		    q.push(t);
		}
	}
	
	printf("%d\n",min(min(dep[4*n+5],dep[4*n+6]),min(dep[4*n+7],dep[4*n+8])));//答案
    return 0;
}

posted @ 2020-01-27 11:30  zhuzihan  阅读(208)  评论(0编辑  收藏  举报