【Ybtoj 第5章 例题4】荆轲刺秦王【广搜】

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


解题思路

调了我一个上午加一个中午的题啊啊啊啊啊!!!

对于每一个点记录{ x , y , c 1 x,y,c1 xyc1隐身使用次数, c 2 c2 c2瞬移使用次数,步数t}

对于一个点,向它能走到的点尝试扩展

  • 没有用瞬移
    新点没有士兵监视,不是士兵, x + w a x [ i ] , y + w a y [ i ] , c 1 , c 2 , t + 1 {x + wax[i], y + way[i], c1, c2, t+1} x+wax[i],y+way[i],c1,c2,t+1
    如果新点是士兵监视,但不是士兵, x + w a x [ i ] , y + w a y [ i ] , c 1 + 1 , c 2 , t + 1 {x + wax[i], y + way[i], c1+1, c2, t+1} x+wax[i],y+way[i],c1+1,c2,t+1

  • 用了瞬移
    新点没有士兵监视,不是士兵, x + w a x [ i ] ∗ d , y + w a y [ i ] ∗ d , c 1 , c 2 + 1 , t + 1 {x + wax[i] * d, y + way[i] * d, c1, c2+1, t+1} x+wax[i]d,y+way[i]d,c1,c2+1,t+1
    如果新点是士兵监视,但不是士兵, x + w a x [ i ] ∗ d , y + w a y [ i ] ∗ d , c 1 + 1 , c 2 + 1 , t + 1 {x + wax[i] * d, y + way[i] * d, c1+1, c2+1, t+1} x+wax[i]d,y+way[i]d,c1+1,c2+1,t+1

  • 剪枝
    走到一个点可能有很多种走法,所以一个点的判重,要判[x][y][c1][c2]有无走过
    答案的优良性包括{t,c1,c2},so第一次走到终点不一定是最优的,但是如果当前队列层的步数已经超过当前最优答案了,就可以直接退出了
    如果方向是偶数,可以尝试瞬移


代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iomanip>
#include <cmath>
using namespace std;

const int dx[8]= {
    
    -1,-1,0,1,1,1,0,-1};
const int dy[8]= {
    
    0,1,1,1,0,-1,-1,-1};

struct c {
    
    
	int c1,c2,t;
}ans;

struct cc {
    
    
	int x,y,c1,c2,t;
}f[5000000];

int h,t,n,m,c1,c2,d,sx,sy,tx,ty,a[500][500],b[500][500],v[500][500][20][20];
string c;

bool check(int x,int y) {
    
    
	if(x>0&&y>0&&x<=n&&y<=m)
		return 1;
	return 0;
}

void answer(int x,int y,int cc1,int cc2,int tt){
    
    
	if(x==tx&&y==ty) 
	{
    
    
		if(tt<ans.t||ans.t==-1)//比当前答案优,或第一次到达终点
			ans.c1=cc1,ans.c2=cc2,ans.t=tt;
		else if(tt==ans.t)
		{
    
    
			if((cc1+cc2)<(ans.c1+ans.c2))//技能数和更少
				ans.c1=cc1,ans.c2=cc2;
			else
			if((cc1+cc2)==(ans.c1+ans.c2)&&cc1<ans.c1)//隐身更少
				ans.c1=cc1,ans.c2=cc2;
		}
	}

}

void bfs() {
    
    
	int xx,yy;
	h=0,t=1;
	f[1].x=sx,f[1].y=sy,v[sx][sy][0][0]=1,ans.t=-1;
	while(h!=t) {
    
    
		h=(h%4999999)+1;
		if(f[h].t>ans.t&&ans.t!=-1)//剪枝:已经超过当前最优答案了
			break;
		answer(f[h].x,f[h].y,f[h].c1,f[h].c2,f[h].t);
		for(int i=0; i<8; i++) {
    
    
			xx=f[h].x+dx[i],yy=f[h].y+dy[i];
			if(check(xx,yy)) {
    
    //不使用瞬移
				if(a[xx][yy]==0)//不在守卫监视范围——不使用隐身
				{
    
    
					if(!v[xx][yy][f[h].c1][f[h].c2])
					{
    
    
						t=(t%4999999)+1;
						f[t]=(cc){
    
    xx,yy,f[h].c1,f[h].c2,f[h].t+1};
						v[xx][yy][f[t].c1][f[t].c2]=1;
					}
				}										
				else if(f[h].c1<c1&&!v[xx][yy][f[h].c1+1][f[h].c2]&&!b[xx][yy])
				{
    
    
					t=(t%4999999)+1;
					f[t]=(cc){
    
    xx,yy,f[h].c1+1,f[h].c2,f[h].t+1};
					v[xx][yy][f[t].c1][f[t].c2]=1;
				}										
			}
			if(!(i%2)&&f[h].c2<c2) {
    
    //使用瞬移,↓同上
				xx=f[h].x+dx[i]*d,yy=f[h].y+dy[i]*d;
				if(check(xx,yy)) {
    
    
					if(a[xx][yy]==0)
					{
    
    
						if(!v[xx][yy][f[h].c1][f[h].c2+1])
						{
    
    
							t=(t%4999999)+1;
							f[t]=(cc){
    
    xx,yy,f[h].c1,f[h].c2+1,f[h].t+1};	
							v[xx][yy][f[t].c1][f[t].c2]=1;
						}
						
					}
					else if(f[h].c1<c1&&!v[xx][yy][f[h].c1+1][f[h].c2+1]&&!b[xx][yy])
					{
    
    
						t=(t%4999999)+1;
						f[t]=(cc){
    
    xx,yy,f[h].c1+1,f[h].c2+1,f[h].t+1};
						v[xx][yy][f[t].c1][f[t].c2]=1;
					}						
				}
			}
		}
	}
}

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>>c;
			if(c==".") 
				continue;
			if(c=="S")
			{
    
    
				sx=i,sy=j;
				continue;
			}				
			else if(c=="T")
			{
    
    
				tx=i,ty=j;
				continue;
			}			
			int w=c[0]-48;
				for(int k=1; k<c.size(); k++)
					w=w*10+c[k]-48;
				for(int ii=max(1,i-w+1); ii<=min(i+w-1,n); ii++)
					for(int jj=max(1,j-w+1); jj<=min(j+w-1,m); jj++)
						if ((abs(ii-i)+abs(jj-j))<w)
							a[ii][jj]++;//标记守卫监视范围
				b[i][j]=1;//标记守卫位置
		}
	}
	bfs();
	if(ans.t!=-1)
		printf("%d %d %d",ans.t,ans.c1,ans.c2);
	else
		printf("-1");
}

猜你喜欢

转载自blog.csdn.net/kejin2019/article/details/113003070