专栏文章

P14469 [COCI 2025/2026 #1] 皇后 / Kraljica 略解

P14469题解参与者 3已保存评论 2

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
2 条
当前快照
1 份
快照标识符
@minb0o29
此快照首次捕获于
2025/12/01 23:28
3 个月前
此快照最后确认于
2025/12/01 23:28
3 个月前
查看原文

思路

如果直接按照题意模拟,每个点最多走一次,每次的扩展时间为 O(n)O(n),时间复杂度是 O(n3)O(n^3) 级别的。
由于点数固定为 n2n ^ 2,无法优化,考虑优化扩展过程:如果此时的点 uu 被扩展出的方向和待扩展的点 vv 的扩展方向相同,相当于代价为 00,否则代价为 11。另外传送门的代价也为 00,所以我们可以记录横纵坐标和当前点被那个方向扩展,使用 0101 BFS 可以很完美的解决这个问题,不会的可以看 P4554 小明的游戏。另外还有一个小细节,起点和传送门出口是没有方向的,可以将方向设为 00

Code

C
//# pragma GCC optimize("Ofast")
# include <bits/stdc++.h>
# define fr front
# define il inline
# define fir first
# define sec second
# define vec vector
# define it iterator
# define pb push_back
# define lb lower_bound
# define ub upper_bound
# define all(x) x.begin(), x.end()
# define mem(a, b) memset(a, b, sizeof(a))

# define lc (t[p].l)
# define rc (t[p].r)
# define ls(x) (x << 1)
# define rs(x) (x << 1 | 1)
# define lson ls(p), l, mid
# define rson rs(p), mid + 1, r

# define sqr(x) ((x) * (x))
# define bpc __builtin_popcount
# define lowbit(x) ((x) & (-(x)))
# define geti(x, i) (((x) >> (i)) & 1)
# define set1(x, i) ((x) | (1 << (i)))
# define set0(x, i) ((x) & (~(1 << (i))))

# define debug1(x) cerr << #x << " = " << x << " "
# define debug2(x) cerr << #x << " = " << x << "\n"
# define bug cerr << "--------------------------\n"

# define each1(i, x) for(auto (i) : (x))
# define each2(i, x) for(auto (&i) : (x))
# define rep(i, a, b) for(int i = (a); i <= (b); ++ i)
# define pre(i, a, b) for(int i = (a); i >= (b); -- i)
# define G(i, h, u, ne) for(int i = (h[(u)]); i; i = (ne[(i)]))
# define reps(i, a, b, c) for(int i = (a); i <= (b); i += (c))
# define pres(i, a, b, c) for(int i = (a); i >= (b); i -= (c))
using namespace std;

using DB = double;
using LL = long long;
using LDB = long double;
using PII = pair<int, int>;
using ULL = unsigned long long;

const int N = 1e3 + 10;
const int INF1 = 0x3f3f3f3f, INF2 = INT_MAX;
const LL INF3 = (LL)1e18, INF4 = 0x3f3f3f3f3f3f3f3f, INF5 = LLONG_MAX;

int n, m, sx, sy, ex, ey, ans;
int vis[N][N][10];

char mp[N][N];

vec<PII> a[10];

int dx[10] = {0, 1, 1, 1, 0, 0, -1, -1, -1};
int dy[10] = {0, -1, 0, 1, -1, 1, -1, 0, 1};

struct node{
	int x, y, dir;
};

void calc(int num, int &x, int &y){//求出编号为num的传送门的相应出口 
	each2(tmp, a[num]){
		if(tmp.fir ^ x || tmp.sec ^ y){
			x = tmp.fir, y = tmp.sec;
			return;
		}
	}
}

void BFS(){
	mem(vis, 0x3f);
	rep(i, 0, 8) vis[sx][sy][i] = 0;
	deque<node> q;
	q.pb({sx, sy, 0});//起点没有方向 
	
	while(!q.empty()){
		int x = q.fr().x, y = q.fr().y, dir = q.fr().dir;
		q.pop_front();
		
		rep(i, 1, 8){
			int nx = x + dx[i], ny = y + dy[i];
			if(nx < 1 || ny < 1 || nx > n || ny > m) continue;
			if(mp[nx][ny] == '#' || vis[nx][ny][i] <= vis[x][y][dir] + (dir != i)) continue;
			vis[nx][ny][i] = vis[x][y][dir] + (dir != i);
			if(dir ^ i) q.pb({nx, ny, i});
			else q.push_front({nx, ny, i});
		}
		
		if('1' <= mp[x][y] && mp[x][y] <= '9'){//传送门 
			int num = mp[x][y] - '0';
			int i = x, j = y;
			calc(num, i, j);
			if(vis[i][j][0] ^ INF1) continue;
			vis[i][j][0] = vis[x][y][dir];
			q.push_front({i, j, 0});//传送门出口方向设为0 
		}
	}
}

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	
	ans = INF1;
	cin >> n >> m;
	
	rep(i, 1, n) cin >> mp[i] + 1;
	
	rep(i, 1, n){
		rep(j, 1, m){
			if(mp[i][j] == 'S') sx = i, sy = j;
			else if(mp[i][j] == 'E') ex = i, ey = j;
			else if(mp[i][j] != '#' && mp[i][j] != '.') a[mp[i][j] - '0'].pb({i, j});
		}
	}
	
	BFS();
	
	rep(i, 0, 8) ans = min(ans, vis[ex][ey][i]);
	
	if(ans ^ INF1) cout << ans;
	else cout << "-1";
	
	return 0;
}
我睜開雙眼,看著空白,忘記妳對我的期待,讀完了依賴,我很快就離開…………

评论

2 条评论,欢迎与作者交流。

正在加载评论...