第一道交互题
题意:
- 生成一个n*n的矩阵(n是奇数), 每个矩阵上的元素是0或1, 你的交互程序要在小于
n
2
n^2
n2个询问中猜出这个矩阵
- 定义询问: x1, y1, x2, y2, 分别代表起点和终点, 而且终点必须在起点的右下方, 而且两者不能不能相邻, 题目会返回在起点和终点的任意一条路径中是否有一条路径是回文串, (路径的方向只能向右或者向下)
- 矩阵的左上角是1, 矩阵的右下角是0;
数据范围:
n
≤
50
n \leq 50
n≤50
前置技能: 无
Tutorial: 不难发现所有横纵坐标之和为偶数的所有坐标都可以被一次询问确定(针对已经确定的x,y, 询问x+2,y或者x+1, y+1, 或者x, y+2, 由于路径的长的是3, 所以是否对称决定始末是否相同), 且如果假设a[1][2] = 0, 那么所有的横纵坐标之和是奇数的也可以被确定(同上), 现在的问题就是验证a[1][2]的假设是否正确, 如果不正确, 应该把所有的横纵坐标之和为奇数的所有值反转
验证过程
#include<bits/stdc++.h>
using namespace std;
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define _rev(i, a, b) for (int i = (a); i >= (b); --i)
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define _rof(i, a, b) for (int i = (a); i > (b); --i)
#define oo 0x3f3f3f3f
#define ll long long
#define db double
#define eps 1e-8
#define bin(x) cout << bitset<10>(x) << endl;
#define what_is(x) cerr << #x << " is " << x << endl;
#define met(a, b) memset(a, b, sizeof(a))
#define all(x) x.begin(), x.end()
#define pii pair<int, int>
const int maxn = 100;
int a[maxn][maxn], n;
bool vis[maxn][maxn], f[maxn][maxn];
int quary(int x1, int y1, int x2, int y2)
{
printf("? %d %d %d %d\n", x1, y1, x2, y2);
fflush(stdout);
int ret;
scanf("%d", &ret);
return ret;
}
vector<pii> q;
void dfs(int x1, int y1, int x2, int y2, int cur)
{
if (vis[x2][y2])
return;
if (x2 == n && y2 == n)
return;
if (x2 > n || y2 > n)
return;
if (x1 != 0 && y1 != 0)
a[x2][y2] = (quary(x1, y1, x2, y2) == 1 ? cur : !cur);
vis[x2][y2] = 1;
dfs(x2, y2, x2 + 2, y2, a[x2][y2]);
dfs(x2, y2, x2 + 1, y2 + 1, a[x2][y2]);
dfs(x2, y2, x2, y2 + 2, a[x2][y2]);
}
bool check(int x1, int y1, int x2, int y2) {
int res = quary(x1, y1, x2, y2);
return (res ? !a[x1][y1] == a[x2][y2] : a[x1][y1] == a[x2][y2]);
}
int cnt;
bool find0(int x, int y)
{
if (x > n || y > n)
return 0;
bool& t = f[x][y];
if (t || vis[x][y])
return t;
vis[x][y] = 1;
if (x + 3 <= n && y <= n)
{
t |= ((a[x][y] ^ a[x + 1][y] ^ a[x + 2][y] ^ a[x + 3][y]) == 0);
if (t) {
q.push_back(make_pair(x, y)), q.push_back(make_pair(x + 3, y));
return t;
}
}
if (x + 2 <= n && y + 1 <= n)
{
t |= ((a[x][y] ^ a[x + 1][y] ^ a[x + 2][y] ^ a[x + 2][y + 1]) == 0);
t |= ((a[x][y] ^ a[x][y + 1] ^ a[x + 1][y + 1] ^ a[x + 2][y + 1]) == 0);
if (t) {
q.push_back(make_pair(x, y)), q.push_back(make_pair(x + 2, y + 1));
return t;
}
}
if (x + 1 <= n && y + 2 <= n)
{
t |= ((a[x][y] ^ a[x + 1][y] ^ a[x + 1][y + 1] ^ a[x + 1][y + 2]) == 0);
t |= ((a[x][y] ^ a[x][y + 1] ^ a[x][y + 2] ^ a[x + 1][y + 2]) == 0);
if (t) {
q.push_back(make_pair(x, y)), q.push_back(make_pair(x + 1, y + 2));
return t;
}
}
if (x <= n && y + 3 <= n)
{
t |= ((a[x][y] ^ a[x][y + 1] ^ a[x][y + 2] ^ a[x][y + 3]) == 0);
if (t) {
q.push_back(make_pair(x, y)), q.push_back(make_pair(x, y + 3));
return t;
}
}
return t || find0(x + 1, y) || find0(x + 1, y + 1) || find0(x, y + 1);
}
void flip()
{
_rep(i, 1, n)
{
for (int j = (i & 1 ? 2 : 1); j <= n; j += 2)
{
a[i][j] = !a[i][j];
}
}
}
signed main()
{
cin >> n;
a[1][1] = 1;
dfs(0, 0, 1, 1, 1);
dfs(0, 0, 1, 2, 0);
for (int i = 2; i <= n; i += 2)
a[i][1] = (quary(i, 1, i + 1, 2) == 1 ? a[i + 1][2] : !a[i + 1][2]);
met(vis, 0);
find0(1, 1);
if (check(q[0].first, q[0].second, q[1].first, q[1].second))
flip();
printf("!\n"),
fflush(stdout);
_rep(i, 1, n) {
_rep(j, 1, n) {
printf("%d", a[i][j]), fflush(stdout);
}
printf("\n"), fflush(stdout);
}
}