【ybtoj】荆轲刺秦王

荆轲刺秦王


题目描述

在这里插入图片描述

输入格式

第一行五个整数 n , m , c 1 , c 2 , d n,m,c_1,c_2,d n,m,c1,c2,d,代表地图的大小为n*m隐身的使用限制次数为 c 1 c_1 c1,瞬移的使用次数为 c 2 c_2 c2,和一次瞬移的距离d。
接下来n行,每行m个元素。每个字符为“S”或“T”或“.”或一个正整数 a i , j a_i,_j ai,j代表一个格点,具体含义详见题目描述。

输出格式

若荆轲无法到达秦王所在点,则输出一行一个 -1。
否则输出一行三个整数 t , u 1 , u 2 t,u_1,u_2 t,u1,u2,依次代表所需的最短时间,隐身的使用次数与瞬移的使用次数。

样例输入

输入样例1

5 4 0 0 5
. 1 T 1
. . . 2
. 1 . .
S . . .
1 . . .

输出样例1

3 0 0

输入样例2

8 6 2 3 3
. S . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
2 . 2 . 2 .
. . 1 . T .
3 . 1 . . 3

输出样例2

3 1 3

解题思路

如果没有技能的使用次数限制,这道题就是个广搜,但这道题加上了次数限制,就不能用(x,y)来描述荆轲的状态了。
这道题还有一个难点就是卫兵观察位置的预处理

#include<cmath>
#include<cstdio>
#include<iostream>
using namespace std;
int n,m,c1,c2,d,ex,ey,answer1=100000,answer2=100000,answer3=100000,answer4=100000,b[400][400],z[400][400],c[400][400][20][20];
int dx[8]= {-1,0,1,0,-1,1,1,-1};
int dy[8]= {0,1,0,-1,1,1,-1,-1};
string s;
struct node {
	int x,y,c1,c2,ans;
} p[10000005];
void fz(int ans,int c1,int c2) {
	answer1=ans;
	answer2=c1;
	answer3=c2;
	answer4=c1+c2;
}
bool check(int x,int y) {
	return x>=1&&x<=n&&y>=1&&y<=m;
}
void bfs() {
	int head=0,tail=1;
	while(head<tail) {
		head++;
		head%=10000000;
		int ox=p[head].x,oy=p[head].y,o1=p[head].c1,o2=p[head].c2,oans=p[head].ans;
		for(int i=0; i<8; i++) {
			int xx=ox+dx[i],yy=oy+dy[i];
			if(check(xx,yy)&&!z[xx][yy]) {
				if(b[xx][yy]) {
					if(o1+1<=c1&&!c[xx][yy][o1+1][o2]) {
						c[xx][yy][o1+1][o2]=1;
						p[++tail]=(node) {
							xx,yy,o1+1,o2,oans+1
						};
						tail%=100000000;
						if(xx==ex&&yy==ey) {
							if(oans+1<answer1)fz(oans+1,o1+1,o2);
							else if(oans+1==answer1&&o1+1+o2<answer4)fz(oans+1,o1+1,o2);
							else if(oans+1==answer1&&o1+1+o2==answer4&&o1+1<answer2)fz(oans+1,o1+1,o2);
						}
					}
				} else {
					if(!c[xx][yy][o1][o2]) {
						c[xx][yy][o1][o2]=1;
						p[++tail]=(node) {
							xx,yy,o1,o2,oans+1
						};
						tail%=100000000;
						if(xx==ex&&yy==ey) {
							if(oans+1<answer1)fz(oans+1,o1,o2);
							else if(oans+1==answer1&&o1+o2<answer4)fz(oans+1,o1,o2);
							else if(oans+1==answer1&&o1+o2==answer4&&o1<answer2)fz(oans+1,o1,o2);
						}
					}
				}
			}
			if(o2+1<=c2&&i<4) {
				int xx=ox+dx[i]*d,yy=oy+dy[i]*d;
				if(check(xx,yy)&&!z[xx][yy]) {
					if(b[xx][yy]) {
						if(o1+1<=c1&&!c[xx][yy][o1+1][o2+1]) {
							c[xx][yy][o1+1][o2+1]=1;
							p[++tail]=(node) {
								xx,yy,o1+1,o2+1,oans+1
							};
							tail%=100000000;
							if(xx==ex&&yy==ey) {
								if(oans+1<answer1)fz(oans+1,o1+1,o2+1);
								else if(oans+1==answer1&&o1+1+o2+1<answer4)fz(oans+1,o1+1,o2+1);
								else if(oans+1==answer1&&o1+1+o2+1==answer4&&o1+1<answer2)fz(oans+1,o1+1,o2+1);
							}
						}
					} else {
						if(!c[xx][yy][o1][o2]) {
							c[xx][yy][o1][o2+1]=1;
							p[++tail]=(node) {
								xx,yy,o1,o2+1,oans+1
							};
							tail%=100000000;
							if(xx==ex&&yy==ey) {
								if(oans+1<answer1)fz(oans+1,o1,o2+1);
								else if(oans+1==answer1&&o1+o2+1<answer4)fz(oans+1,o1,o2+1);
								else if(oans+1==answer1&&o1+o2+1==answer4&&o1<answer2)fz(oans+1,o1,o2+1);
							}
						}
					}
				}
			}
		}
	}
	return;
}
int main() {
	scanf("%d%d%d%d%d",&n,&m,&c1,&c2,&d);
	for(int i=1; i<=n; i++)
		for(int j=1; j<=m; j++) {
			cin>>s;
			if(s[0]=='S')p[1]=(node) {i,j,0,0},c[i][j][0][0]=1;
			else if(s[0]=='T')ex=i,ey=j;
			else if(s[0]!='.') {
				int len=s.size(),sum=0;
				z[i][j]=1;
				for(int k=0; k<len; k++)
					sum=sum*10+s[k]-48;
				for(int x=max(1,i-sum); x<=min(n,i+sum); x++)
					for(int y=max(1,j-sum); y<=min(m,j+sum); y++)
						if(abs(i-x)+abs(j-y)<sum)
							b[x][y]=1;
			}
		}
	bfs();
	if(answer1==100000)printf("-1");
	else printf("%d %d %d",answer1,answer2,answer3);
	return 0;
}

谢谢阅读

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值