交互题。
题意:你放置一个皇后的位置,不知道国王的初始位置。国王会向八个方向行动,每次国王先行,双方都必须移动。任何时刻国王都不能移动到皇后的攻击位置。你需要在不管国王怎样移动情况下都保证在有限步数内击败对方。
solution: 比较棘手的是不知道国王的位置。但是真的有必要知道它的位置吗?
比较容易想到的是蛇形走位。假设当前在第 i i i 行 ,那么 1 − i 1-i 1−i 行都已经被占领了。我们从第一列开始,从左往右扫一遍,看看会发生什么:
- 若国王在第 i + 1 i+1 i+1 列,显然会被逼迫到选择 Down , Down-Left , Right-Down 以躲避攻击。此时可以趁机占领 i + 1 i+1 i+1 列。
- 若国王在 ≥ 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 7∗8+8∗8+8=128 步。
一个坑点是,走到当前行的第一个位置是不能算的。
- 优化1:发现检查一列时可以一次走两个位置,这样常数减少一半。
- 优化2:我们还可以 启发式搜索 ,维护当前国王可能的位置坐标。如果 i + 1 − j i+1-j i+1−j 行全为 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();
}
}