bzoj1967 [AHOI2005]穿越磁场 离散最短路

这个题难点在于离散的角度,一开始想的是对联通块离散,但由于联通块形态不一,所以只能dfs,效率为4e8

所以我们可以离散  直线间的间距,这样也就相当于离散了dfs的过程

所以线段的题有一个套路就是离散间距、、


注:

分清>号和>=号


码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
using namespace std;
map<int,int>mx,my;
queue<int>q;
#define N 180000
int tot,j,sx,zy,k,hou[N*4],xia[N],cnt,lx,ly,n,xx[N],yy[N],x[N],y[N],c[N],zhong[N*4],v[N*4],i,d[N],st,xxx,yyy,xxxx,yyyy;
void jia(int a,int b,int c)
{
	++tot,hou[tot]=xia[a],xia[a]=tot,v[tot]=c,zhong[tot]=b;
}
int bfs(int qd)
{
	q.push(qd);
  for(i=1;i<=90000;i++)d[i]=99999;
	d[qd]=0;
	while(!q.empty())
	{
		st=q.front();
		q.pop();
		for(i=xia[st];i!=-1;i=hou[i])
		{
			int nd=zhong[i];
			if(d[nd]<=d[st]+v[i])continue;
			d[nd]=d[st]+v[i];
			q.push(nd);		
		}	
	}
	return d[mx[xxxx]+my[yyyy]*300];
}
int main()
{
	memset(xia,-1,sizeof(xia));
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
		scanf("%d%d%d",&y[i],&x[i],&c[i]);
		xx[++cnt]=x[i],yy[cnt]=y[i];
		xx[++cnt]=x[i]+c[i],yy[cnt]=y[i]+c[i];
	}
	scanf("%d%d%d%d",&yyy,&xxx,&yyyy,&xxxx);
	xx[++cnt]=xxx;yy[cnt]=yyy;	xx[++cnt]=xxxx;yy[cnt]=yyyy;
	sort(xx+1,xx+1+cnt);
	sort(yy+1,yy+1+cnt);
	mx[xx[1]]=3;my[yy[1]]=3;
	lx=3;ly=3;
	for(i=2;i<=cnt;i++)
	{
	if(xx[i]!=xx[i-1])
	{
		if(xx[i]==xx[i-1]+1)lx++;
		else lx+=2;
		mx[xx[i]]=lx;
    }
	if(yy[i]!=yy[i-1])
	{
		if(yy[i]==yy[i-1]+1)ly++;
		else ly+=2;
		my[yy[i]]=ly;
    }	
	}
//	cout<<cnt;
	for(i=1;i<=lx+2;i++)
	for(j=1;j<=ly+2;j++)
	{sx=zy=0;
	//cout<<i<<" "<<j<<"     ";
		for(k=1;k<=n;k++)
		{ //cout<<my[y[k]]<<" "<<my[y[k]+c[k]]<<" ";
			if(my[y[k]]<=j&&my[y[k]+c[k]]>=j)
			{
				if(i==mx[x[k]]||i==mx[x[k]+c[k]])
				{
					sx=k;
				}
			} //cout<<mx[x[k]]<<" "<<mx[x[k]+c[k]];
			if(mx[x[k]]<=i&&mx[x[k]+c[k]]>=i)
			{
				if(j==my[y[k]]||j==my[y[k]+c[k]])
				{
					zy=k;
				}
			}
		}
		if(sx==0&&zy==0)jia(i+300*j,i-1+300*j,0),jia(i+300*j,i+1+300*j,0),jia(i+300*j,i+300*(j+1),0),jia(i+300*j,i+300*(j-1),0);
	if(sx&&zy)continue;
	if(sx)	jia(i+300*j,i-1+300*j,1),jia(i+300*j,i+1+300*j,1);
	if(zy)	jia(i+300*j,i+300*(j+1),1),jia(i+300*j,i+300*(j-1),1);					
	}
printf("%d",bfs(mx[xxx]+my[yyy]*300));
	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值