Loading

方阵贪吃蛇的必胜策略

包含本题的交互题单

https://qoj.ac/contest/3588/problem/17759

一道上次深圳 ICPC 的交互,感觉是签到,因为我同学去打了但是我没去,我太菜了,欢迎且膜拜全国各地来深圳比赛的选手。

就是传统的贪吃蛇,不能碰墙,每一次移动之后头不可以和身体某一部分重合(特别地,如果长度为 \(2\),调换蛇的方向并不会违反这个规定)。身体增长是体现在:造成进食的那一步本身,蛇的尾部不会空出来。

给你初始坐标和每一次吃完苹果后下一个苹果出现的位置(只会出现在空位)。让你返回贪吃蛇的走法,你需要使得你可以最终使贪吃蛇填满屏幕(交互体现在这个东西是在线的,你必须要吃完目前的苹果才会给你下一个苹果的坐标,并且你目前蛇的形态会影响评测机下一次给你的坐标)。

强化问题:我们想构造一个回路,使得其经过所有点刚好一次。这样让蛇头沿着这条回路一直走就好了。

然后就是黑白染色分析,得出以下结论。

  • 考虑如果有至少一条边是偶数,可以直接构造如下图的方案。

Screenshot 2026-04-29 1

  • 如果两条边都是奇数呢?尝试构造。

Screenshot 2026-04-29 223438

然后根据苹果的位置,每次可以走橙线/红线。

因为最后一次吃之前只剩一格,一定是在橙红线中没有被走的那个上出现,然后发现这时拐进去吃刚好会填满整张图,不会碰到蛇本身,于是问题解决。

代码(对于奇数情况,我后面找到了一个更好写的构造方法,于是和上述不一样,所以主要看一下实现方式):

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 57;
int dx[] = {1, 0, -1, 0};
int dy[] = {0, 1, 0, -1};
//D, R, U, L
map<char, int> mp;
map<char, char> tr;
int vis[N][N], n, m;
char a[N][N];
void solve(){
	int f = 0;
	cin >> n >> m;
	mp['D'] = 0, mp['R'] = 1, mp['U'] = 2, mp['L'] = 3;
	tr['D'] = 'D', tr['R'] = 'R', tr['U'] = 'U', tr['L'] = 'L';
	for(int i = 1; i <= max(n, m); i ++)
		for(int j = 1; j <= max(n, m); j ++) vis[i][j] = 1;
	if((n & 1) && (m & 1)){
		for(int i = 1; i < m; i ++) a[1][i] = 'R';
		a[1][m] = 'D';
		for(int i = m; i > 2; i --){
			if(i & 1){
				for(int j = 2; j < n; j ++) a[j][i] = 'D';
				a[n][i] = 'L';
			}
			else{
				for(int j = n; j > 2; j --) a[j][i] = 'U';
				a[2][i] = 'L';
			}
		}
		for(int i = n; i > 1; i --){
			if(i & 1) a[i][1] = 'U', a[i][2] = 'L';
			else a[i][1] = 'R', a[i][2] = 'U';
		}
		vis[1][1] = 0;
	}
	else{
		if(!(m & 1)){
			swap(n, m), f = 1;
			swap(tr['R'], tr['D']);
			swap(tr['U'], tr['L']);
		}
		for(int i = n; i >= 2; i --) a[i][1] = 'U';
		a[1][1] = 'R';
		for(int i = 1; i <= n; i += 2){
			for(int j = 2; j < m; j ++) a[i][j] = 'R';
			a[i][m] = 'D';
			for(int j = m; j > 2; j --) a[i + 1][j] = 'L';
			a[i + 1][2] = 'D';
		}
		a[n][2] = 'L';
	}
	int x, y; cin >> x >> y;
	if(f) swap(x, y);
	int cnt = n * m - 1;
	while(cnt --){
		int r, c; cin >> r >> c;
		if(f) swap(r, c);
		if(!vis[r][c]){
			a[2][1] = 'U' + 'R' - a[2][1];
			vis[1][1] = 1 - vis[1][1], vis[2][2] = 1 - vis[2][2];
		}
		while(x != r || y != c){
			int dir = mp[a[x][y]];
			cout << tr[a[x][y]];
			x += dx[dir], y += dy[dir];
		}
		cout << endl;
	}
}
signed main(){
  ios::sync_with_stdio(0), cin.tie(0);
  int t; cin >> t;
  while(t --) solve();
  return 0;
}
posted @ 2026-04-29 22:54  Trent900  阅读(59)  评论(3)    收藏  举报