洛谷 3831 [SHOI2012]回家的路 题解

该博客详细解析了SHOI2012比赛中的回家的路问题,涉及二维矩阵上的路径规划。题设中,矩阵中的特定关键点允许转弯,从一个格子移动到相邻格子需花费2,转弯花费1。博主通过新建起点和终点节点,拆分并连接节点来构建图,最后利用最短路径算法求解最小花费。若无解则输出-1。

博客观赏效果更佳

题意简述

n n n n n n 列的矩阵上,只有 m m m 个“关键点”处(在第 x x x y y y 列)才能拐弯。从格子到上下左右四个相邻格子花费 2 2 2,转弯花费 1 1 1。 求从某个位置走到另一个位置的最小花费。无解输出 − 1 -1 1

思路

新建两个点 S S S T T T 表示起点。 然后把所有点 A A A(包括关键点和 S , T S,T S,T) 拆成两个点 A 1 A_1 A1 A 2 A_2 A2,分别表示横向跑和纵向跑。

对于所有关键点 K K K (不包括 S , T S,T S,T), K 1 K_1 K1 K 2 K_2 K2 连一条边权为 1 1 1 的无向边,表示换乘。

然后对于所有同一行 ( x x x 相同)的点,按照列号 y y y 排序。对于相邻的 A , B A,B A,B,连边 ( A 1 , B 1 , 2 × d i s ) (A_1,B_1,2\times dis) (A1,B1,2×dis),其中 d i s dis dis A , B A,B A,B 两点 y y y 值的距离。为啥乘二,是因为相邻格子要花费 2 2 2。 同一列同理(同一列连的是 A 2 A_2 A2 B 2 B_2 B2)。

然后我们从 S 1 S_1 S1 跑到 T 1 , T 2 T_1,T_2 T1,T2,从 S 2 S_2 S2 跑到 T 1 , T 2 T_1,T_2 T1,T2 ,四种方案,看哪个最小。如果都不能到达…那就输出 − 1 -1 1

代码

#include <bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
	#define N 255555
	#define F(i,l,r) for(int i=l;i<=r;++i)
	#define D(i,r,l) for(int i=r;i>=l;--i)
	#define Fs(i,l,r,c) for(int i=l;i<=r;c)
	#define Ds(i,r,l,c) for(int i=r;i>=l;c)
	#define MEM(x,a) memset(x,a,sizeof(x))
	#define FK(x) MEM(x,0)
	#define Tra(i,u) for(int i=G.Start(u),v=G.To(i);~i;i=G.Next(i),v=G.To(i))
	#define p_b push_back
	#define sz(a) ((int)a.size())
	#define iter(a,p) (a.begin()+p)
	int I()
	{
	    int x=0;char c=getchar();int f=1;
	    while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
	    while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	    return (x=(f==1)?x:-x);
	}
	void Rd(int cnt,...)
	{
	    va_list args; va_start(args,cnt);
	    F(i,1,cnt) {int* x=va_arg(args,int*);(*x)=I();}
	    va_end(args);
	}
	class Graph
	{
	    public:
	        int head[N];
	        int EdgeCount;
	        struct Edge
	        {
	            int To,Label,Next;
	        }Ed[1666666];
	        void clear(int _V=N,int _E=N<<1) 
	        {
	            memset(Ed,-1,sizeof(Edge)*(_E));
	            memset(head,-1,sizeof(int)*(_V));
	            EdgeCount=-1;
	        }
	        void AddEdge(int u,int v,int w=1)
	        {
	            Ed[++EdgeCount]=(Edge){v,w,head[u]};
	            head[u]=EdgeCount;
	        }
	        void Add2(int u,int v,int w=1) 
	        {
	        	// printf("Add %d %d\n",u,v);
	        	AddEdge(u,v,w);AddEdge(v,u,w);
	        }
	        int Start(int u) {return head[u];}
	        int To(int u){return Ed[u].To;}
	        int Label(int u){return Ed[u].Label;}
	        int Next(int u){return Ed[u].Next;}
	}G;
	struct node{int x,y,id;}a[N]; 
	bool cmp_x(node a,node b) {return a.x<b.x or (a.x==b.x and a.y<b.y);}
	bool cmp_y(node a,node b) {return a.y<b.y or (a.y==b.y and a.x<b.x);}
	#define lin(x) x
	#define col(x) (x)+m+2

	int n,m;
	void Input()
	{
		Rd(2,&n,&m); F(i,1,m) a[i]=(node){I(),I(),i};
		a[m+1]=(node){I(),I(),m+1};
		a[m+2]=(node){I(),I(),m+2};
	}

	void Build()
	{
		G.clear();
		sort(a+1,a+m+3,cmp_x);
		F(i,2,m+2) if (a[i].x==a[i-1].x) G.Add2(lin(a[i].id),lin(a[i-1].id),2*abs(a[i].y-a[i-1].y));
		sort(a+1,a+m+3,cmp_y);
		F(i,2,m+2) if (a[i].y==a[i-1].y) G.Add2(col(a[i].id),col(a[i-1].id),2*abs(a[i].x-a[i-1].x));
		F(i,1,m+2) if (a[i].id<=m) G.Add2(lin(a[i].id),col(a[i].id),1); 
	}
	struct djnode{int v,w;}; bool operator<(djnode a,djnode b){return a.w>b.w;}
	priority_queue<djnode> Q; bool vis[N];int dis[N];
	void Dijkstra(int s)
	{
		MEM(dis,0x3f); FK(vis); while(!Q.empty()) Q.pop();
		Q.push((djnode){s,0}); dis[s]=0;
		while(!Q.empty())
		{
			djnode Min=Q.top(); Q.pop();
			int u=Min.v;	
			if (vis[u]) continue;
			vis[u]=1;

			Tra(i,u) if (!vis[v] and dis[v]>dis[u]+G.Label(i)) 
			{
				dis[v]=dis[u]+G.Label(i);
				Q.push((djnode){v,dis[v]});
			}
		}
		// F(i,1,2*(m+2)) printf("%d ",dis[i]>1e9?-1:dis[i]);
		// putchar('\n'); 
	}
	void Soviet()
	{
		Build();
		int ans=0x3f3f3f3f;
		Dijkstra(lin(m+1)); ans=min(ans,min(dis[lin(m+2)],dis[col(m+2)]));
		Dijkstra(col(m+1)); ans=min(ans,min(dis[lin(m+2)],dis[col(m+2)]));
		printf("%d\n",ans>1e9?-1:ans);
	}

	#define Flan void
	Flan IsMyWife()
	{
		Input();
		Soviet();
	}
}
int main()
{
	Flandre_Scarlet::IsMyWife();
	getchar();getchar();
	return 0;
}
先看效果: https://renmaiwang.cn/s/jkhfz Hue系列产品将具备高度的个性化定制能力,并且借助内置红、蓝、绿三原色LED的灯泡,能够混合生成1600万种不同色彩的灯光。 整个操作流程完全由安装于iPhone上的应用程序进行管理。 这一创新举措为智能照明控制领域带来了新的启示,国内相关领域的从业者也积极投身于相关研究。 鉴于Hue产品采用WiFi无线连接方式,而国内WiFi网络尚未全面覆盖,本研究选择应用更为普及的蓝牙技术,通过手机蓝牙与单片机进行数据交互,进而产生可调节占空比的PWM信号,以此来控制LED驱动电,实现LED的调光功能以及DIY调色方案。 本文重点阐述了一种基于手机蓝牙通信的LED灯设计方案,该方案受到飞利浦Hue智能灯泡的启发,但考虑到国内WiFi网络的覆盖限制,故而选用更为通用的蓝牙技术。 以下为相关技术细节的详尽介绍:1. **智能照明控制系统**:智能照明控制系统允许用户借助手机应用程序实现远程控制照明设备,提供个性化的调光及色彩调整功能。 飞利浦Hue作为行业领先者,通过红、蓝、绿三原色LED的混合,能够呈现1600万种颜色,实现了全面的定制化体验。 2. **蓝牙通信技术**:蓝牙技术是一种低成本、短距离的无线传输方案,工作于2.4GHz ISM频段,具备即插即用和强抗干扰能力。 蓝牙协议栈由硬件层和软件层构成,提供通用访问Profile、服务发现应用Profile以及串口Profiles等丰富功能,确保不同设备间的良好互操作性。 3. **脉冲宽度调制调光**:脉冲宽度调制(PWM)是一种高效能的调光方式,通过调节脉冲宽度来控制LED的亮度。 当PWM频率超过200Hz时,人眼无法察觉明显的闪烁现象。 占空比指的...
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值