弹指间计算机协会 X Five Pines Robomaster实验室 考核题面与题解

大一组

绩点

Description

阿杰在大一学习了C++入门课程,这门课程的总绩点计算方法为:

总绩点=作业分数× 20% +小测分数× 30% +期末考试分数× 50%

阿杰想知道,这门课程的最终绩点。

Input

输入只有1行,包含三个非负整数A、B、C,分别表示阿杰的作业成绩、小测

分数和期末考试分数。相邻两个数之间用一个空格隔开,三项分数满分都是100分。

Output

输出只有1行,包含一个整数,即阿杰这门课程的总绩点,满分也是100分。

Sample Input 1

100 100 80

Sample Output 1

90

Sample Input 2

60 90 80

Sample Output 2

79

代码

#include<iostream>
using namespace std;
int a,b,c;
int main(){
    
    
	cin>>a>>b>>c;
 	int res=0.2*a+0.3*b+0.5*c;
   cout<<res<<endl;
  return 0;
}

字符串统计

Description

给定一个字符串,要求统计字符串的字符

注意:字符串中可能包含大、小写英文字母、数字字符、空格和换行符。统计字符串字符数时,空格和换行符不计算在内。

Input

输入只有一行,一个字符串s。

Output

输出只有一行,包含一个整数,即作文标题的字符数(不含空格和换行符)。

Sample Input 1

234

Sample Output 1

3

Sample Input 2

Ca 45

Sample Output 2

4

Hint

【输入输出样例2说明】

字符串中共有5个字符,包括1个大写英文字母,

1个小写英文字母和2个数字字符,

还有1个空格。由于空格不计入结果中,故标题的有效字符数为4个。

【数据规模与约定】

规定|s|表示字符串s的长度(即字符串中的字符和空格数)。

对于40%的数据,1 ≤ |s| ≤ 5,保证输入为数字字符及行末换行符。

对于80%的数据,1 ≤ |s| ≤ 5,输入只可能包含大、小写英文字母、数字字符及行末换行符。

对于100%的数据,1 ≤ |s| ≤ 5,输入可能包含大、小写英文字母、数字字符、空格和行末换行符。

代码

#include<iostream>
#include<cstring>
using namespace std;
int main(){
    
    
	string s;
    getline(cin,s);
  	int res=0;
    for(int i=0;i<s.size();i++)
      if (s[i]!=' '&&s[i]!='\n')
      	res++;
    cout<<res;
  return 0;
}

报销

Description

Min找老师报销费用。第一天,Min给老师一张发票;

之后两天(第二天和第三天),每天给老师两张发票;

之后三天(第四、五、六天),每天给老师三张发票;

之后四天(第七、八、九、十天),每天给老师四张发票……;

这种报销模式会一直这样延续下去:当连续N天每天收到N张发票后,老师会在之后的连续N+1天里,每天收到N+1张发票。

请计算在前K天里,老师一共获得了多少发票。

Input

输入只有1行,包含一个正整数K,表示上交发票的天数。

Output

输出只有1行,包含一个正整数,即老师收到的发票数。

Sample Input 1

5

Sample Output 1

11

Sample Input 2

1000

Sample Output 2

29820

Hint

【输入输出样例1说明】

老师第一天收到一张发票;第二天和第三天,每天收到两张发票;第四、五天,

每天收到三张发票。因此一共收到1+2+2+3+3=11张发票。

【数据说明】

对于100%的数据,1≤K≤10,000。

代码

#include<iostream>
using namespace std;
int n;
long long res=0;
int main(){
    
    
	cin>>n;
    int j=0,k=0;
    for(int i=1;i<=10000&&i<=n;i++)
    	for(int j=0;j<i&&k<n;j++,k++)
        	res+=i;
  cout<<res;
}

质因数分解

Description

已知正整数n是两个不同的质数的乘积,试求出较大的那个质数。

Input

输入只有一行,包含一个正整数n。

Output

输出只有一行,包含一个正整数p,即较大的那个质数。

Sample Input 1

21

Sample Output 1

7

Hint

对于60%的数据,6 ≤ n ≤ 1000。

对于100%的数据,6 ≤ n ≤ 2 × 10 9 2 \times {10}^9 2×109

代码

#include<iostream>
using namespace std;
int main(){
    
    
	long long n;
	cin>>n;
	for(long long i=2;i*i<=n;i++){
    
    
		if (n%i==0){
    
    
			cout<<n/i;
			return 0;
		}
	}
} 

骨牌(此题已砍)

Description

在一个有 2 ∗ n 2*n 2n个格子的大长方形槽内放置 1 ∗ 2 1*2 12的小骨牌,骨牌可以横放可以竖放,有多少种不同的放置方式可以将大长方形槽填满?

例如,当 n = 3 n=3 n=3时,一共有3种方式。
在这里插入图片描述

Input

输入只有一行,包含一个正整数n。

Output

输出只有一行,包含一个正整数res,即结果

Sample Input 1

3

Sample Output 1

3

Hint

对于100%的数据,1 ≤ n ≤ 50

题解

n = 1 n=1 n=1,有且只有一种摆法

n = 2 n=2 n=2,可以两个横放,也可以两个竖放,有二种摆法

n = 3 n=3 n=3,可以由 n = 2 n=2 n=2的情况再竖放一个骨牌得到,也可以由 n = 1 n=1 n=1的情况再横放两个骨牌得到(不能竖放两个骨牌,会与 n = 2 n=2 n=2的情况重复)。

以此类推, f n = f n − 1 + f n − 2 f_n=f_{n-1}+f_{n-2} fn=fn1+fn2

代码

#include<iostream>
using namespace std;
long long f[55];
int main(){
    
    
	f[1]=1;
	f[2]=2;
	int n;
	cin>>n;
	for(int i=3;i<=n;i++)
		f[i]=f[i-1]+f[i-2];
	cout<<f[n];
	return 0;
}

复数

Description

给定两个复数 a + b i a+bi a+bi c + d i c+di c+di ,求他们相加,相减,相乘后的结果

注意,本题要求必须使用class(类)来完成复数的定义

Input

输入共一行,为4个整数,从左至右分别为a,b,c,d,用空格隔开,代表两个复数a+bi, c+di

Output

输出共三行,从上到下分别为 a + b i a+bi a+bi c + d i c+di c+di的和,差,积

输出形式为“ m ± n i m±ni m±ni”,如 3 + 4 i , 6 − 9 i , − 2 − 7 i , − 1 + 1 i 3+4i, 6-9i, -2-7i, -1+1i 3+4i,69i,27i,1+1i

特别地,当实部为0时,只输出虚部,如 4 i , − 1 i 4i, -1i 4i,1i

当虚部为0时,只输出实部,如 − 5 , 1 -5, 1 5,1

当实部虚部均为0时,输出 0 0 0

Sample Input 1

1 2 3 4

Sample Output 1

4+6i
-2-2i
-5+10i

Sample Input 2

1 0 1 1

Sample Output 2

2+1i
-1i
1+1i

Hint

数据范围:

对于100%的测试用例, − 10000 < a , b , c , d < 10000 -10000 \lt a,b,c,d \lt 10000 10000<a,b,c,d<10000其中 a , b , c , d ∈ Z a,b,c,d \in Z a,b,c,dZ

代码

#include<iostream>
#include<cstdio>
using namespace std;
class Complex {
    
    
public:
    int m, n;
    Complex operator+(Complex& c2) {
    
    
        Complex res;
        res.m = m + c2.m;
        res.n = n + c2.n;
        return res;
    }
    Complex operator-(Complex& c2) {
    
    
        Complex res;
        res.m = m - c2.m;
        res.n = n - c2.n;
        return res;
    }
    Complex operator*(Complex& c2) {
    
    
        Complex res;
        res.m = m * c2.m - n * c2.n;
        res.n = n * c2.m + m * c2.n;
        return res;
    }
    void cprint() {
    
    
        if (m == 0 && n == 0)
            printf("0\n");
        else if (m == 0 && n != 0)
            printf("%di\n", n);
        else if (m != 0 && n == 0)
            printf("%d\n", m);
        else printf("%d%+di\n", m, n);
    }

};

int main() {
    
    
    Complex c1, c2;
    cin >> c1.m >> c1.n >> c2.m >> c2.n;
    Complex c3 = c1 + c2;
    c3.cprint();
    c3 = c1 - c2;
    c3.cprint();
    c3 = c1 * c2;
    c3.cprint();
    return 0;
}

大二组

韭菜

Description

在今后的几天内Jerry将学习美元与人民币的汇率。编写程序帮助Jerry何时应买或卖人民币或美元,使他从100美元开始,最后能获得最高可能的价值。

Input

第一行是一个自然数N,1≤N≤100,表示Jerry学习汇率的天数。

接下来的N行中每行是一个自然数A,1≤A≤1000。第i+1行的A表示预先知道的第i+1天的平均汇率,在这一天中,Jerry既能用100美元买A人民币也能用A人民币购买100美元。

Output

第一行也是唯一的一行应输出要求的钱数(单位为美元,保留两位小数)。

注意:Jerry必须在最后一天结束之前将他的钱都换成美元。

Sample Input 1

5
400
300
500
300
250

Sample Output 1

266.67

Hint

样例解释

Day 1 … changing 100.0000美元= 400.0000人民币

Day 2 … changing 400.0000人民币= 133.3333美元

Day 3 … changing 133.3333美元= 666.6666人民币

Day 5 … changing 666.6666人民币= 266.6666美元

题解

状态机dp

钱有两种状态:美元,记为0状态。RMB,记为1状态。记 f i , 0 f_{i,0} fi,0表示最优策略下第 i i i天的美元数量, f i , 1 f_{i,1} fi,1表示最优策略下第 i i i天的人民币数量。

设第 i i i天汇率汇率为 a i a_i ai,在最优策略下:当第 i − 1 i-1 i1天汇率>第 i i i天,可以把人民币兑换成美元 f i , 0 = f i − 1 , 1 / a i f_{i,0}=f_{i-1,1}/a_i fi,0=fi1,1/ai。当第 i − 1 i-1 i1天汇率<第 i i i天,可以把美元兑换为人民币 f i , 1 = f i − 1 , 0 ∗ a i f_{i,1}=f_{i-1,0}*a_i fi,1=fi1,0ai

i i i的维度优化掉,得到最终递推关系:
{ f 0 = f 1 / a i a i − 1 > a i f 1 = f 0 ∗ a i a i − 1 < a i \begin{cases} f_0=f_1/a_i&a_{i-1}>a_i\\ f_1=f_0*a_i&a_{i-1}<a_i \end{cases} { f0=f1/aif1=f0aiai1>aiai1<ai
在最后一天,一定会把所有的钱都换成美元,则值为 f 0 f_0 f0 f 1 / a n f_1/a_n f1/an

代码

#include<iostream>
using namespace std;
double f[2];//0为美元,1为rmb 
double a[1005];
double st=1;
int n;
int main(){
    
    
	cin>>n;
	for(int i=1;i<=n;i++){
    
    
		cin>>a[i];
		a[i]=a[i]/100.0;
	}
	f[0]=100;
	f[1]=100*a[1];
	for(int i=2;i<=n;i++){
    
    
		if (a[i-1]<a[i]){
    
    
			f[1]=f[0]*a[i];		
		}
		if (a[i-1]>a[i]){
    
    
			f[0]=f[1]/a[i];
		}
//		cout<<"day"<<i<<":"<<f[0]<<"美元"<<f[1]<<"人民币\n"; 
	}
	double res=max(f[0],f[1]/a[n]);
	printf("%.2f",res);
	return 0;
}

闭合区域面积统计

Description

编程计算由‘*’号围成的下列图形的面积。面积的计算方法是统计*号所围成

的闭合曲线中水平线和垂直线交点的数目。如图所示,在10*10的二维数组中,

有*围住了15个点,因此面积为15。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tx3AJSua-1668250987661)(https://ujscoder.club/public/upload/40c420fcf8.png)]

Input

一个10*10的二维数组,里面的数为0和1,1代表着*号 。

Output

一个整数,代表被围住的点个数。

Sample Input 1

0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 1 1 0 0 0
0 0 0 0 1 0 0 1 0 0
0 0 0 0 0 1 0 0 1 0
0 0 1 0 0 0 1 0 1 0
0 1 0 1 0 1 0 0 1 0
0 1 0 0 1 1 0 1 1 0
0 0 1 0 0 0 0 1 0 0
0 0 0 1 1 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0

Sample Output 1

15

题解

bfs,从左上角、右上角、左下角、右下角为起点找到外圈的0,再找出1的个数,则剩下的0的个数就是被1包围的0

代码

#include<iostream>
#include<queue>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
int map[10][10];
int dx[4]={
    
    -1,0,1,0};
int dy[4]={
    
    0,1,0,-1};
int cnt0=0,cnt1=0;
int st[10][10];
void bfs0(){
    
    
	queue<PII> q;
  	if (map[0][0]==0)
		q.push({
    
    0,0});
    if (map[0][9]==0)
  		q.push({
    
    0,9});
    if (map[9][0]==0)
	  	q.push({
    
    9,0});
  	if (map[9][9]==0)  
  		q.push({
    
    9,9});
	while(!q.empty()){
    
    
		PII p=q.front();
		q.pop();
		st[p.x][p.y]=1;
		cnt0++;
//		cout<<p.x<<" "<<p.y<<endl;
		for(int k=0;k<4;k++){
    
    
			int newx=p.x+dx[k];
			int newy=p.y+dy[k];
			if (newx<0||newx>=10||newy<0||newy>=10)
				continue;
			if (st[newx][newy])
				continue;
			if (map[newx][newy]==1)
				continue;
			q.push({
    
    newx,newy});
			st[newx][newy]=1;
		}
	}
}
int main(){
    
    
	for(int i=0;i<10;i++)
		for(int j=0;j<10;j++)
			cin>>map[i][j];
	bfs0();
	for(int i=0;i<10;i++)
		for(int j=0;j<10;j++){
    
    
			if (map[i][j]==1)
				cnt1++;
		}
//	cout<<cnt0<<endl<<cnt1<<endl;
	int res=100-cnt0-cnt1;
	cout<<res;
}

晒衣服

Description

熊大妈需要给宝宝们晒衣服。

衣服在自然条件下用 1 的时间可以晒干 A 点湿度。抠门的熊大妈买了 1 台烘衣机。使用烘衣机可以让你用单位 1 时间使 1件衣服除开自然晒干的 A 点湿度外,还可烘干 B 点湿度,但在单位 1 时间内只能对 1 件衣服使用。

N 件的衣服因为种种原因而不一样湿,现在告诉你每件衣服的湿度,要你求出弄干所有衣服的最少时间(湿度为 0 为干)。

Input

第一行N,A ,B , 接下来N行 ,每行一个正整数 ,表示衣服的湿度(1<= 湿度,A,B<=500000,1<=N<=500000)。

Output

一个正整数,表示弄干衣服的最小时间

Sample Input 1

3 2 1
1
2
3

Sample Output 1

1

Hint

对于40%的测试用例,n <= 5000

对于70%的测试用例,n <= 10000

对于全部的测试用例,n <= 500000

【样例解析】

第 1 个时间内,用机器处理第 3 件衣服,此外,所有衣服自然晒干 2。花费 1 时间全部弄干。

题解

建大根堆,模拟。堆顶为(不考虑自然风干的情况下)湿度最大的衣服,(不考虑自然风干时)当前湿度记为 m m m。记当前时间为 t t t,当 m − t ∗ a ≤ 0 m-t*a\le 0 mta0时,表示衣服已经自然晒干。否则,对它用烘干机, m ← m − b m\leftarrow m-b mmb,塞回堆内,计时。

代码

#include<iostream>
#include<queue>
#include<vector>
using namespace std;
int main(){
    
    
	int n,a,b;
	cin>>n>>a>>b;
	priority_queue<int> q;
	for(int i=1;i<=n;i++){
    
    
		int shidu;
		cin>>shidu;
		q.push(shidu);
	}
	int t=0;
	do{
    
    
      	int p=q.top();
      	q.pop();
      	if (p-a*t<=0)
			break;
		t++;
		p-=b;
     	q.push(p);
	}while(1);
	cout<<t<<endl;
}

奶酪

Description

现有一块大奶酪,它的高度为 h h h,它的长度和宽度我们可以认为是无限大的,奶酪中间有许多半径相同的球形空洞。我们可以在这块奶酪中建立空间坐标系,在坐标系中,奶酪的下表面为 z = 0 z=0 z=0,奶酪的上表面为 z = h z=h z=h

现在,奶酪的下表面有一只小老鼠 Jerry,它知道奶酪中所有空洞的球心所在的坐标。如果两个空洞相切或是相交,则 Jerry 可以从其中一个空洞跑到另一个空洞,特别地,如果一个空洞与下表面相切或是相交,Jerry 则可以从奶酪下表面跑进空洞;如果一个空洞与上表面相切或是相交,Jerry 则可以从空洞跑到奶酪上表面。

位于奶酪下表面的 Jerry 想知道,在不破坏奶酪的情况下,能否利用已有的空洞跑 到奶酪的上表面去?

空间内两点 P 1 ( x 1 , y 1 , z 1 ) P_1(x_1,y_1,z_1) P1(x1,y1,z1) P 2 ( x 2 , y 2 , z 2 ) P2(x_2,y_2,z_2) P2(x2,y2,z2) 的距离公式如下:

d i s t ( P 1 , P 2 ) = ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 + ( z 1 − z 2 ) 2 \mathrm{dist}(P_1,P_2)=\sqrt{(x_1-x_2)^2+(y_1-y_2)^2+(z_1-z_2)^2} dist(P1,P2)=(x1x2)2+(y1y2)2+(z1z2)2

Input

每个输入文件包含多组数据。

第一行,包含一个正整数 T T T,代表该输入文件中所含的数据组数。

接下来是 T T TT组数据,每组数据的格式如下: 第一行包含三个正整数 n , h , r n,h,r n,h,r,两个数之间以一个空格分开,分别代表奶酪中空洞的数量,奶酪的高度和空洞的半径。

接下来的 n n n行,每行包含三个整数 x , y , z x,y,z x,y,z,两个数之间以一个空格分开,表示空洞球心坐标为$ (x,y,z)$。

Output

T T T 行,分别对应 T T T 组数据的答案,如果在第 i i i 组数据中,Jerry 能从下表面跑到上表面,则输出 Yes,如果不能,则输出 No

Sample Input 1

3 
2 4 1 
0 0 1 
0 0 3 
2 5 1 
0 0 1 
0 0 4 
2 5 2 
0 0 2 
2 0 4

Sample Output 1

Yes
No
Yes

Hint

在这里插入图片描述

第一组数据,由奶酪的剖面图可见:

第一个空洞在 ( 0 , 0 , 0 ) (0,0,0) (0,0,0) 与下表面相切;

第二个空洞在 ( 0 , 0 , 4 ) (0,0,4) (0,0,4) 与上表面相切;

两个空洞在 ( 0 , 0 , 2 ) (0,0,2) (0,0,2) 相切。

输出 Yes

第二组数据,由奶酪的剖面图可见:

两个空洞既不相交也不相切。

输出 No

第三组数据,由奶酪的剖面图可见:

两个空洞相交,且与上下表面相切或相交。

输出 Yes

【数据规模与约定】

对于 20 % 20\% 20% 的数据, n = 1 n = 1 n=1 1 ≤ h 1 \le h 1h r ≤ 1 0 4 r \le 10^4 r104,坐标的绝对值不超过 1 0 4 10^4 104

对于 40 % 40\% 40% 的数据, 1 ≤ n ≤ 8 1 \le n \le 8 1n8 1 ≤ h 1 \le h 1h r ≤ 1 0 4 r \le 10^4 r104,坐标的绝对值不超过 1 0 4 10^4 104

对于 80 % 80\% 80% 的数据, 1 ≤ n ≤ 1 0 3 1 \le n \le 10^3 1n103 1 ≤ h 1 \le h 1h , r ≤ 1 0 4 r \le 10^4 r104,坐标的绝对值不超过 1 0 4 10^4 104

对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1 × 1 0 3 1 \le n \le 1\times 10^3 1n1×103 1 ≤ h 1 \le h 1h , r ≤ 1 0 9 r \le 10^9 r109 T ≤ 20 T \le 20 T20,坐标的绝对值不超过 1 0 9 10^9 109

题解

建图,设0号点为起点, n + 1 n+1 n+1号点为终点。将每个洞视为图中的点。若洞高度绝对值小于半径 r r r,则起点连到该点。若洞高度大于 h − r h-r hr,则该点连到终点。若距离小于半径的两倍,则两个洞所代表的点连一条边。建图完成后,dfs

代码

#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
using namespace std;
typedef long long ll;
vector<int> G[1005];
double ball[1005][4];
bool st[1005];
void dfs(int i){
    
    
	st[i]=1;
	for(auto node:G[i]){
    
    
		if (!st[node])
			dfs(node);
	}
}
signed main(){
    
    
	freopen("res.in","r",stdin);
	freopen("res.out","w",stdout);
	int t;
	cin>>t;
	while(t--){
    
    
		memset(ball,0,sizeof ball);
		memset(st,0,sizeof st);
		int n;
		double h,r;
		cin>>n>>h>>r;
		for(int i=0;i<=n+1;i++)
			G[i].clear(); 
		for(int i=1;i<=n;i++){
    
    
			cin>>ball[i][1]>>ball[i][2]>>ball[i][3];
		}
		for(int i=1;i<=n;i++){
    
    
			if (ball[i][3]<=r){
    
    
				G[0].push_back(i);//0号点为起点,底边
			 	G[i].push_back(0);
			}
			if (ball[i][3]>=h-r){
    
    
				G[n+1].push_back(i);//n+1号点为终点 
				G[i].push_back(n+1);
			}
			for(int j=i+1;j<=n;j++){
    
    
				double sqrdst=(ball[i][1]-ball[j][1])*(ball[i][1]-ball[j][1])
						  +(ball[i][2]-ball[j][2])*(ball[i][2]-ball[j][2])
						  +(ball[i][3]-ball[j][3])*(ball[i][3]-ball[j][3]);
				if (sqrdst<=4*r*r){
    
    
					G[i].push_back(j);
					G[j].push_back(i);
				}
			}
		}
		dfs(0);
		if (st[n+1])
			cout<<"Yes\n";
		else
			cout<<"No\n";
	}
}

机器人搬重物

Description

机器人移动学会 RMI 现在正尝试用机器人搬运物品。机器人的形状是一个直径 1.6 1.6 1.6 米的球。在试验阶段,机器人被用于在一个储藏室中搬运货物。储藏室是一个 N × M N \times M N×M 的网格,有些格子为不可移动的障碍。机器人的中心总是在格点上,当然,机器人必须在最短的时间内把物品搬运到指定的地方。机器人接受的指令有:向前移动 1 1 1 步 Creep;向前移动 2 2 2步 Walk;向前移动 3 3 3 步 Run;向左转 Left;向右转 Right。每个指令所需要的时间为 1 1 1 秒。请你计算一下机器人完成任务所需的最少时间。

Input

第一行为两个正整数 N , M ( N , M ≤ 50 ) N,M(N,M \le 50) N,M(N,M50),下面 N N N行是储藏室的构造, 0 0 0表示无障碍, 1 1 1表示有障碍,数字之间用一个空格隔开。接着一行有 4 4 4个整数和 1 1 1个大写字母,分别为起始点和目标点左上角网格的行与列,起始时的面对方向(东E,南S,西W,北N),数与数,数与字母之间均用一个空格隔开。终点的面向方向是任意的。

Output

一个整数,表示机器人完成任务所需的最少时间。如果无法到达,输出 − 1 -1 1

img

Sample Input 1

9 10
0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 1 0
0 0 0 1 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 1 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 1 0
7 2 2 7 S

Sample Output 1

12

题解

bfs。对于每个点,需要记录的是每一种朝向时所需的步数。某个点某朝向的步数第一次被更新时,一定是最优解。由于障碍物在格子里而机器人在格子交叉点里,所以需要判断机器人是否撞墙/撞障碍物。对于机器人位置 ( x , y ) (x,y) (x,y),则 ( x − 1 , y − 1 ) , ( x − 1 , y ) , ( x , y − 1 ) , ( x , y ) (x-1,y-1),(x-1,y),(x,y-1),(x,y) (x1,y1),(x1,y),(x,y1),(x,y)位置的障碍物都不能撞到。也不能撞墙,即需要满足 0 < x < n , 0 < y < m 0< x < n,0<y < m 0<x<n,0<y<m

代码

#include<iostream>
#include<queue>
#include<cstring>
#include<map>
#include<iomanip>
using namespace std;
struct posd{
    
    
	int x, y, d;
};
int collidx[4] = {
    
     -1, 0,-1,0 };//障碍物
int collidy[4] = {
    
     -1,-1, 0,0 };
int dx[4] = {
    
     -1,1,0,0 };
int dy[4] = {
    
     0,0,-1,1 };
int dist[55][55][4];//0 北 1南 2西 3东
map<char, int> c2i = {
    
    {
    
    'N',0},{
    
    'S',1},{
    
    'W',2},{
    
    'E',3}};
int ditu[55][55];
int n, m;
bool collide(int x, int y) {
    
    
	if (x == 0 || y == 0 || x >= n || y >= m)
		return true;
	for (int k = 0;k < 4;k++) {
    
    
		int tx = x + collidx[k];
		int ty = y + collidy[k];
		if (ditu[tx][ty] == 1)
			return true;
	}
	return false;
}
int main() {
    
    
	cin >> n >> m;
	for (int i = 0;i < n;i++)
		for (int j = 0;j < m;j++)
			cin >> ditu[i][j];
	int startx, starty, endx, endy;
	char startd;
	cin >> startx >> starty >> endx >> endy;
	cin >> startd;
	memset(dist, 0x3f3f3f3f, sizeof dist);
	queue<posd> q;
	q.push({
    
     startx,starty,c2i[startd] });
	dist[startx][starty][c2i[startd]] = 0;
	while (!q.empty()) {
    
    
		auto p= q.front();
		q.pop();
		if (p.d == 0 || p.d == 1) {
    
    //从南北转到东西
			if (dist[p.x][p.y][2] == 0x3f3f3f3f) {
    
    
				dist[p.x][p.y][2] = dist[p.x][p.y][p.d] + 1;
				q.push({
    
     p.x,p.y,2 });
			}
			if (dist[p.x][p.y][3] == 0x3f3f3f3f) {
    
    
				dist[p.x][p.y][3] = dist[p.x][p.y][p.d] + 1;
				q.push({
    
     p.x,p.y,3 });
			}
		}
		if (p.d == 2 || p.d == 3) {
    
    //从东西转到南北
			if (dist[p.x][p.y][0] == 0x3f3f3f3f) {
    
    
				dist[p.x][p.y][0] = dist[p.x][p.y][p.d] + 1;
				q.push({
    
     p.x,p.y,0 });
			}
			if (dist[p.x][p.y][1] == 0x3f3f3f3f) {
    
    
				dist[p.x][p.y][1] = dist[p.x][p.y][p.d] + 1;
				q.push({
    
     p.x,p.y,1 });
			}
		}
		//往对应方向走1/2/3步
		int tx = p.x, ty = p.y;
		for (int _ = 0;_ <3;_++) {
    
    
			tx +=dx[p.d];
			ty +=dy[p.d];
			if (collide(tx, ty))
				break;
			if (dist[tx][ty][p.d] != 0x3f3f3f3f)
				continue;
			dist[tx][ty][p.d] = dist[p.x][p.y][p.d] + 1;
			q.push({
    
     tx,ty,p.d });
		}
	}
	int res = 0x3f3f3f3f;
	for (int k = 0;k < 4;k++)
		res = min(res, dist[endx][endy][k]);
    if (res==0x3f3f3f3f)
      	cout<<-1;
    else 
		cout << res << endl;
}

猜你喜欢

转载自blog.csdn.net/qq_46640863/article/details/127823937