【题解】CF1557E Assiut Chess

交互题。

题意:你放置一个皇后的位置,不知道国王的初始位置。国王会向八个方向行动,每次国王先行,双方都必须移动。任何时刻国王都不能移动到皇后的攻击位置。你需要在不管国王怎样移动情况下都保证在有限步数内击败对方。

solution: 比较棘手的是不知道国王的位置。但是真的有必要知道它的位置吗?

比较容易想到的是蛇形走位。假设当前在第 i i i 行 ,那么 1 − i 1-i 1i 行都已经被占领了。我们从第一列开始,从左往右扫一遍,看看会发生什么:

  1. 若国王在第 i + 1 i+1 i+1 列,显然会被逼迫到选择 Down , Down-Left , Right-Down 以躲避攻击。此时可以趁机占领 i + 1 i+1 i+1 列。
  2. 若国王在 ≥ i + 2 \geq i+2 i+2 列,同时没有向下走的话,我们可以占领 i + 1 i+1 i+1 列;如果选择 Up, Up-Left, Up-Right 之一,我们重新从第 1 1 1 列开始从左往右扫,重复上述操作。

根据势能分析,国王到我方的纵向距离单调不增,所以总步数不会超过 7 ∗ 8 + 8 ∗ 8 + 8 = 128 7*8+8*8+8=128 78+88+8=128 步。

一个坑点是,走到当前行的第一个位置是不能算的。

  • 优化1:发现检查一列时可以一次走两个位置,这样常数减少一半。
  • 优化2:我们还可以 启发式搜索 ,维护当前国王可能的位置坐标。如果 i + 1 − j i+1-j i+1j 行全为 0 0 0 的话就直接跳到第 j j j 行,否则找到第一个 ( i + 1 , p ) = 1 (i+1,p)=1 (i+1,p)=1 的点,然后移动到 ( i , p ) (i,p) (i,p) 。具体编码比较复杂,可以用 队列 来实现。这样的话步数大概在 15 15 15 步左右。还有一个细节就是如果对方是 Up, Up-Left, Up-Right 的话,要重复上述操作。

下次做交互题一定要一遍过。。。

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define PII pair<int,int>
#define ll long long
using namespace std;
int dx[16],dy[16];
void solve() {
	int x,y=1;
	for(x=1;x<=8;x++) {
		int ok(0); 
		cout<<x<<" "<<y<<endl;
		string op; cin>>op;
		if(op=="Done") return;
		y=(y==1)?3:1;
		while(y<=7) {
			cout<<x<<" "<<y<<endl;
			string op; cin>>op;
			if(op=="Done") return;
			if(op[0]=='D') {
				ok=1;
				break;
			}
			if(op[0]=='U') {
				y=(y==1)?3:1;
				continue;
			}
			//对方没有向上下移动,说明不在 x+1 行 
			if(y==7) {
			    ok=1;
			    break;
			} 
			else y+=2;
		}
	}
}
signed main() {
//	freopen("data.in","r",stdin);
    for(int i=0;i<7;i++) dx[i]=1,dy[i]=0;
    dy[7]=-1;
    for(int i=8;i<15;i++) dx[i]=-1;
	dy[15]=-1; 
	int T; scanf("%d",&T); 
	while(T--) {
		solve();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值