P1686 挑战(推荐洛谷水紫)

原题链接

P1686 挑战

题目大意

有一条路径,使用 E , W , S , N E,W,S,N E,W,S,N 来表示( E E E 向东, W W W 向西, S S S 向南, N N N 向北)。找一条最短的捷径可以连接其中非连续的两点(捷径必须是直的,并且起始点和终止点的x或y坐标相同),若有多个答案,输出开始点标号最小的那一条,若任然有多个答案,输出结束点标号最大的那一条,如:
P1686 挑战(推荐洛谷水紫)
答案即是:
P1686 挑战(推荐洛谷水紫)

解题思路

题目描述中,显眼的括号告诉了我们答案:

(捷径必须是直的,并且起始点和终止点的x或y坐标相同)

如何让起始点和终止点的x坐标相同?很简单,只需要按照x坐标当做第一关键字排一次序。如何让起始点和终止点的y坐标相同?也只需要按照y坐标当做第一关键字排一次序。
那么到底输出什么答案?其实,也只需要按照题目意思(求最短的捷径,若有多个答案,输出开始点标号最小的那一条,若任然有多个答案,输出结束点标号最大的那一条)再排一次序。

代码实现

//注意:本代码中x,y坐标表示的意义相反
#include<iostream>
#include<fstream>
#include<set>
#include<map>
#include<ctime>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
typedef long long ll;
struct node{
	ll x,y,id;
} xy[250010];
struct node2{
	ll lenth,s,e;
	char way;
};
struct node3{
	ll x,y;
};
vector<node2> ans;
char c;
char ans_way;
int ans_len=0x7fffffff,ans_b=-0x7fffffff,ans_a=0x7fffffff,n;
node chk(char c)
{
	return ((c=='E')?(node){0,1}:((c=='W')?(node){0,-1}:((c=='S')?(node){1,0}:(node){-1,0})));
}
bool pd1(node q,node h)
{
	if(q.x!=h.x)
		return q.x<h.x;
	return q.y<h.y;
}
bool pd2(node q,node h)
{
	if(q.y!=h.y)
		return q.y<h.y;
	return q.x<h.x;
}
bool pd3(node2 q,node2 h)
{
	if(q.lenth!=h.lenth)//长度最短
		return q.lenth<h.lenth;
	if(q.s!=h.s)//开始点标号最小
		return q.s<h.s;
	return q.e>h.e;//结束点标号最大
}
char chk_ans(node3 q,node3 h)//q为起始点,h为终止点,判断路线方向
{
	if(q.x<h.x)
		return 'S';//向南
	if(q.x>h.x)
		return 'N';//向北
	if(q.y<h.y)
		return 'E';//向东
	return 'W';//向西
}
void work1()//寻找朝向东或西的捷径
{
	for(int i=1;i<n;i++){
		if(xy[i].x==xy[i+1].x&&min(xy[i].id,xy[i+1].id)+1!=max(xy[i].id,xy[i+1].id)){
			if(xy[i].id<xy[i+1].id)//判断起始点和终止点
				ans.push_back((node2){abs(xy[i].y-xy[i+1].y),xy[i].id,xy[i+1].id,chk_ans((node3){xy[i].x,xy[i].y},(node3){xy[i+1].x,xy[i+1].y})});//记录答案
			else
				ans.push_back((node2){abs(xy[i].y-xy[i+1].y),xy[i+1].id,xy[i].id,chk_ans((node3){xy[i+1].x,xy[i+1].y},(node3){xy[i].x,xy[i].y})});//记录答案
		}
	}
}
void work2()//寻找朝向南或北的捷径
{
	for(int i=1;i<n;i++){
		if(xy[i].y==xy[i+1].y&&min(xy[i].id,xy[i+1].id)+1!=max(xy[i].id,xy[i+1].id)){//y坐标相同,且非向连续
			if(xy[i].id<xy[i+1].id)//判断起始点和终止点
				ans.push_back((node2){abs(xy[i].x-xy[i+1].x),xy[i].id,xy[i+1].id,chk_ans((node3){xy[i].x,xy[i].y},(node3){xy[i+1].x,xy[i+1].y})});//记录答案
			else
				ans.push_back((node2){abs(xy[i].x-xy[i+1].x),xy[i+1].id,xy[i].id,chk_ans((node3){xy[i+1].x,xy[i+1].y},(node3){xy[i].x,xy[i].y})});//记录答案
		}
	}
}
int main()
{
	cin>>n;
	xy[0].x=250005;
	xy[0].y=250005;
	for(int i=1;i<=n;i++){
		cin>>c;
		node change=chk(c);
		xy[i].x=xy[i-1].x+change.x;//模拟路径
		xy[i].y=xy[i-1].y+change.y;//模拟路径
		xy[i].id=i;
	}
	sort(xy+1,xy+n+1,pd1);//以x为第一关键字排序
	work1();
	sort(xy+1,xy+n+1,pd2);//以y为第一关键字排序
	work2();
	sort(ans.begin(),ans.end(),pd3);//排序答案
	cout<<ans[0].lenth<<" "<<ans[0].s<<" "<<ans[0].e<<" "<<ans[0].way;
	return 0;
}

样例

输出

12
NNNENNWWWSSW

输出

2 3 11 W
上一篇:电子罗盘——平面上磁力计的校准


下一篇:Leetcode1247. 交换字符使得字符串相同