51nod1572 宝岛地图 预处理

本文介绍了一个基于算法的寻宝挑战,玩家需要在一个由海和陆地组成的岛屿地图上,根据一系列指令找到宝藏的位置。文章详细解释了输入输出格式及解决思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目来源: CodeForces
基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题
收藏
关注

勇敢的水手们到达了一个小岛,在这个小岛上,曾经有海盗在这里埋下了一些宝藏。然而,我们的船快抛锚了,与此同时,船长发现藏宝图的一角被老鼠咬掉了一块。

 

藏宝图可以用一个n×m大小的矩形表示。矩形中的每一小块表示小岛中的一小块陆地(方块的边长为1米)。有一些方块表示的是海,这些块人是不能通过的。除了海不能走,其它的小方块都是可以行走的。在可行走区域里有一些小方块表示一些已知的地点。

 

另外,在地图上有k条指令。每条指令的格式表示如下:

“向y方向走n米”。

 

这里的方向有四种:“北”,“南”,“东”,“西”。如果你正确的跟着这些指令行走,并且完整的执行完所有指令,你就可以找到宝藏所在的地点。

 

但是,很不幸,由于地图中好多地方都缺失了,船长也不知道从哪些地方开始走。但是船长依然清楚地记得一些已知的地点。另外,船长也知道所有可行走区域。

 

现在船长想知道从哪些已知地点出发,按照指令,可能找到宝藏所在地。




Input


单组测试数据第一行包含两整数n和m(3≤n,m≤1000)。接下来的n行每行有m个字符,表示整个地图。“#”代表海。在地图矩形中,矩形的四周一圈一定是海。“.”代表可行走区域,未知地点。大写字母“A”到“Z”表示可行走区域,已知地点。所有大写字母不一定都被用到。每个字母在地图中最多出现一次。所有已知地点用不同的大写字母表示。接下来一行有一个整数k(1≤k≤10^5),接下来有k行。每行表示一条指令。指令格式为“dir len”,“dir”表示朝哪个方向走,“len”表示走几步。“dir”有四种取值“N”,“S”,“E”,“W”,对应题目中的“北”,“南”,“东”,“西”在地图中,北是在顶部,南是在底部,西是在左边,东是在右边。“len”是一个整数,范围在[1,1000]。


Output


共一行,按字典序升序打印出所有可以完整执行地图中指令的已知区域的字母,如果没有满足要求的已知区域,则打印“no solution”(没有引号)。


Input示例


输入样例16 10###########K#..######.#..##.###..L.#...####D###A.###########4N 2S 1E 1W 2


Output示例


输出样例1AD


思路:预处理每个位置四个方向能够走几步(这个不要暴力,会TE),然后暴力。
Code:
#include <bits/stdc++.h>
using namespace std;
const int AX = 1e3+6;
char G[AX][AX];
int step[AX][AX][5];
set<char>se;
map<char,int>mp;
struct Node
{
	char c;
	int v;
}dir[100002];
int main(){
	mp['N'] = 0;
	mp['S'] = 1;
	mp['W'] = 2;
	mp['E'] = 3;
	int n , m , K ;
	scanf("%d%d",&n,&m);
	for( int i = 0 ; i < n ; i ++ ){
		scanf("%s",G[i]);
	}
	scanf("%d",&K);
	for( int i = 0 ; i < K ; i ++ ){
		cin >> dir[i].c >> dir[i].v;
	}
	// ↑ ↓ ← →
	for( int i = 0 ; i < n ; i++ ){
		for( int j = 0 ; j < m ; j++ ){
			if( G[i][j] == '#' ){
				step[i][j][0] = -1;
				step[i][j][1] = -1;
				step[i][j][2] = -1;
				step[i][j][3] = -1;
			}
		}
	}
	for( int i = 0 ; i < n ; i++ ){
		for( int j = 0 ; j < m ; j++ ){
			if( G[i][j] != '#' ){
				step[i][j][0] = step[i-1][j][0] + 1;
				step[i][j][2] = step[i][j-1][2] + 1;
			}
		}
	}
	for( int i = n-1 ; i >= 0 ; i --  ){
		for( int j = m-1 ; j >= 0 ; j -- ){
			if( G[i][j] != '#' ){
				step[i][j][1] = step[i+1][j][1] + 1;
				step[i][j][3] = step[i][j+1][3] + 1;
			}
		}
	}
	for( int i = 0 ; i < n ; i++ ){
		for( int j = 0 ; j < m ; j++ ){
			if( G[i][j] >= 'A' && G[i][j] <= 'Z' ){
				int falg = 1;
				int x = i , y = j;
				for( int k = 0 ; k < K ; k++ ){
					int tmp = mp[dir[k].c];
					if( step[x][y][tmp] < dir[k].v ){
						falg = 0; break;
					}else{
						if( tmp == 0 ) x -= dir[k].v;
						else if( tmp == 1 ) x += dir[k].v;
						else if( tmp == 2 ) y -= dir[k].v;
						else if( tmp == 3 ) y += dir[k].v;
					}
				}
				if( falg ) se.insert(G[i][j]);
			}
		}
	}
	if( se.size() ){
		set<char>::iterator it;
		for( it = se.begin() ; it != se.end() ; it++ ){
			cout << *it ;
		}	
	}else{
		cout << "no solution";
	}
	cout << endl;
	return 0;
}


题目 51nod 3478 涉及一个矩阵问题,要求通过最少的操作次数,使得矩阵中至少有 `RowCount` 行和 `ColumnCount` 列是回文的。解决这个问题的关键在于如何高效地枚举所有可能的行和列组合,并计算每种组合所需的操作次数。 ### 解法思路 1. **预处理每一行和每一列变为回文所需的最少操作次数**: - 对于每一行,计算将其变为回文所需的最少操作次数。这可以通过比较每对对称位置的值是否相同来完成。 - 对于每一列,计算将其变为回文所需的最少操作次数,方法同上。 2. **枚举所有可能的行和列组合**: - 由于 `N` 和 `M` 的最大值为 8,因此可以枚举所有可能的行组合和列组合。 - 对于每一种组合,计算其所需的最少操作次数,并取最小值。 3. **计算操作次数**: - 对于每一种组合,需要计算哪些行和列需要修改,并且注意行和列的交叉点可能会重复计算,因此需要去重。 ### 代码实现 以下是一个可能的实现方式,使用了枚举和位运算来处理组合问题: ```python def min_operations_to_palindrome(matrix, row_count, col_count): import itertools N = len(matrix) M = len(matrix[0]) # Precompute the cost to make each row a palindrome row_cost = [] for i in range(N): cost = 0 for j in range(M // 2): if matrix[i][j] != matrix[i][M - 1 - j]: cost += 1 row_cost.append(cost) # Precompute the cost to make each column a palindrome col_cost = [] for j in range(M): cost = 0 for i in range(N // 2): if matrix[i][j] != matrix[N - 1 - i][j]: cost += 1 col_cost.append(cost) min_total_cost = float('inf') # Enumerate all combinations of rows and columns rows = list(range(N)) cols = list(range(M)) from itertools import combinations for row_comb in combinations(rows, row_count): for col_comb in combinations(cols, col_count): # Calculate the cost for this combination cost = 0 # Add row costs for r in row_comb: cost += row_cost[r] # Add column costs for c in col_comb: cost += col_cost[c] # Subtract the overlapping cells for r in row_comb: for c in col_comb: # Check if this cell is part of the palindrome calculation if r < N // 2 and c < M // 2: if matrix[r][c] != matrix[r][M - 1 - c] and matrix[N - 1 - r][c] != matrix[N - 1 - r][M - 1 - c]: cost -= 1 min_total_cost = min(min_total_cost, cost) return min_total_cost # Example usage matrix = [ [0, 1, 0], [1, 0, 1], [0, 1, 0] ] row_count = 2 col_count = 2 result = min_operations_to_palindrome(matrix, row_count, col_count) print(result) ``` ### 代码说明 - **预处理成本**:首先计算每一行和每一列变为回文所需的最少操作次数。 - **枚举组合**:使用 `itertools.combinations` 枚举所有可能的行和列组合。 - **计算成本**:对于每一种组合,计算其成本,并考虑行和列交叉点的重复计算问题。 ### 复杂度分析 - **时间复杂度**:由于 `N` 和 `M` 的最大值为 8,因此枚举所有组合的时间复杂度为 $ O(N^{RowCount} \times M^{ColCount}) $,这在实际中是可接受的。 - **空间复杂度**:主要是存储预处理的成本,空间复杂度为 $ O(N + M) $。 ### 相关问题 1. 如何优化矩阵中行和列的枚举组合以减少计算时间? 2. 在计算行和列的交叉点时,如何更高效地处理重复计算的问题? 3. 如果矩阵的大小增加到更大的范围,如何调整算法以保持效率? 4. 如何处理矩阵中行和列的回文条件不同时的情况? 5. 如何扩展算法以支持更多的操作类型,例如翻转某个区域的值?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值