[Astar2015]下棋

下棋

 Time Limit: 6000/3000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
Problem Description

NM 的棋盘上有一个受伤的国王与一个要去救援国王的骑士,他们每个单位时间必须同时移动一次寻找对方。如下图所示,黑色的图例表示国王(右)或骑士(左)当前所在的位置,那么灰色的位置表示在一次移动中他们可能到达的位置。国王伤势严重,因此他必须在K个单位时间内得到骑士的救援,否则会挂掉。问国王是否可以在K个单位时间内获得救援,如果可以,最短需要花多少个单位时间。

Input

第一行包含一个整数 T,1T50 代表测试数据的组数,接下来 T 组测试数据。

每组测试数据第一行包含三个整数 N,M,K , 且 2N,M1000 1K200 。第二行两个整数 Xking,Yking ,对应国王所在方格的坐标。第三行两个整数 Xknight,Yknight ,对应骑士所在方格的坐标。其中 1Xking,XknightN,1Yking,YknightM ,保证骑士与国王一开始不在同一个方格内且他们都可以移动。:

Output

对于每组测试数据,输出两行:

第一行输出:"Case #i:"。 i 代表第 i 组测试数据。

第二行输出测试数据的结果,如果国王可以得到救援,则输出最快需要花多少个单位时间。否则,输出“OH,NO!”。

Sample Input
2
3 2 1
1 1
3 1
3 3 1
1 1
1 2 
Sample Output
Case #1:
1
Case #2:
OH,NO!

这个题感觉还是很有意思的。

注意到马跳到一个位置所需步数的奇偶性是不能发生改变的,因为其每跳一步x+y的奇偶性是一定会发生改变的。而对于国王来说,如果国王走k步能到一个位置,那么国王走>=k步一定能到这个位置。所以我们可以首先BFS出王和马到一个位置的最短步数,然后枚举每一个位置。判断一下,如果是王先到这里,那么马到这里的步数就是它们在这里相遇的最短步数;如果是马先到这里,那么最小的大于等于王的步数且与马的最短步数奇偶性相同的数就是王和马在这里相遇的最短时间。

#include<cstdio>
#include<iostream>
using namespace std;
#include<cstring>
int d[2][1005][1005];
int qx[1000005],qy[1000005];
int dx[2][10]={{1,2,1,2,-1,-2,-1,-2},{1,1,1,0,0,-1,-1,-1}},dy[2][10]={{2,1,-2,-1,2,1,-2,-1},{1,0,-1,1,-1,1,0,-1}};
int N,M;
bool check(int x,int y){
	return x>0&&x<=N&&y>0&&y<=M;
}
int main(){
	int T,K;
	scanf("%d",&T);
	int x[5],y[5],h,t,i,j,D,ans,tmp;
	for(int Case=1;Case<=T;++Case){
		scanf("%d%d%d%d%d%d%d",&N,&M,&K,x+1,y+1,x,y);
		memset(d,127,sizeof(d));
		for(D=0;D<2;++D){
			qx[0]=x[D],qy[0]=y[D],d[D][x[D]][y[D]]=0;
			for(h=0,t=1;h!=t&&d[D][qx[h]][qy[h]]<K;++h)
				for(i=0;i<8;++i)
					if(check(qx[t]=qx[h]+dx[D][i],qy[t]=qy[h]+dy[D][i])&&d[D][qx[t]][qy[t]]>1E5){
						d[D][qx[t]][qy[t]]=d[D][qx[h]][qy[h]]+1;
						++t;
					}
		}
		ans=0x7fffffff;
		for(i=N;i;--i)
			for(j=M;j;--j){
				if(d[0][i][j]<=d[1][i][j])ans=min(ans,d[1][i][j]+(d[0][i][j]&1^d[1][i][j]&1));
				else if(d[0][i][j]>1)ans=min(ans,d[0][i][j]);
			}
		printf("Case #%d:\n",Case);
		if(ans<=K)printf("%d\n",ans);
		else puts("OH,NO!");
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值