c++算法题:综合
拯救公主
百炼OJ, 题目链接
思路,典型的bfs问题,但需要处理的条件较多,此种题适合使用结构体来做,注意熟练使用结构体编程。
先贴上代码,以后再多写几遍,这里用到了状态压缩的方法记录宝石的数量。
#include <iostream>
#include <cstring>
#include <queue>
#include <map>
using namespace std;
#define MAX 201
char a[MAX][MAX];
struct Node
{
int x, y; //坐标。
int num = 0; //存储宝石数目。
int deep = 0; //搜索深度。
Node() {
}
Node(int xx, int yy, int gg, int dd) : x(xx), y(yy), num(gg), deep(dd) {
}
};
int dir[4][2] = {
{
0, -1},{
-1, 0},{
0, 1},{
1, 0}};
int visited[MAX][MAX][1 << 5 - 1]; //宝石数目最大11111
int r, c, k, doorCount;
Node doors[11];
int bit1Count(int value) {
unsigned int count = 0;
while (value > 0) {
// until all bits are zero
if ((value & 1) == 1) // check lower bit
count++;
value >>= 1; // shift bits, removing lower bit
}
return count;
}
void printQueue(std::queue<Node> q) {
while (!q.empty()) {
Node node = q.front();
q.pop();
cout << "(" << node.x << ", " << node.y << ", "
<< bit1Count(node.num) << ", " << node.deep << ") ";
}
cout << endl << endl;
}
int getTarget(Node* node, Node* endNode) {
return (node->x == endNode->x && node->y == endNode->y && bit1Count(node->num) >= k);
}
int bfs(Node* startNode, Node* endNode) {
if (startNode == NULL || endNode == NULL) return -1;
memset(visited, 0, sizeof(visited));
visited[startNode->x][startNode->y][0] = 1; //置起点已经访问
queue<Node> q;
q.push(*startNode); //起点入队
while (!q.empty()) {
Node node = q.front(); //取队首元素,出队
q.pop();
for (int i = 0; i < 4; i++) {
// 遍历四个方向
int newX = node.x + dir[i][0];
int newY = node.y + dir[i][1];
if (newX < 0 || newX >= r || newY < 0 || newY >= c) continue; // 越界则下一个
if (a[newX][newY] == '#' || visited[newX][newY][node.num]==1) continue; //碰到墙或者已经访问过,则下一个
//不是墙壁并且此节点没访问过
visited[newX][newY][node.num] = 1;
// 当前路可走
Node newNode(newX, newY, node.num, node.deep + 1);
if (a[newX][newY] >= '0' && a[newX][newY] <= '4') {
// 遇到宝石
newNode.num |= 1 << (a[newX][newY] - '0'); //状态压缩记录宝石数量
}
if ((newNode.x == endNode->x && newNode.y == endNode->y && bit1Count(newNode.num) >= k)) {
return newNode.deep;
}
// 没有达到终点,则当前点入队
q.push(newNode);
//如果是传送门的话就将所有其它传送门也加入搜索队列。
if (a[newX][newY] == '$') {
for (int j = 0; j < doorCount; j++) {
Node currNode = doors[j];
if (currNode.x == newX && currNode.y == newY) continue;
Node doorNode(currNode.x, currNode.y, newNode.num, newNode.deep);
q.push(doorNode);
}
}
}
}
return -1;
}
int main() {
int t;
cin >> t; //t组数据
while (t--) {
// Node记录坐标,宝石数目,深度
Node *startNode = NULL, *endNode = NULL;
cin >> r >> c >> k; //r*c矩阵,k个宝石
doorCount = 0;
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
cin >> a[i][j];
switch (a[i][j]) {
case '$': //记录所有传送门的位置。
doors[doorCount++] = Node(i, j, 0, 0);
break;
case 'S': // 记录起点位置
startNode = new Node(i, j, 0, 0);
break;
case 'E': // 记录终点位置
endNode = new Node(i, j, 0, 0);
}
}
}
int ans=bfs(startNode, endNode);
ans == -1 ? (cout << "oop!" << endl) : (cout << ans << endl);
}
return 0;
}
#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
using namespace std;
//16.57
struct Node{
int x,y; // 坐标
int num; // 宝石个数
int depth; // 深度
Node(){
}
Node(int xx,int yy,int nn,int dd) :x(xx),y(yy),num(nn),depth(dd) {
}
};
int R,C,K,ct=0;
//vector<vector<char>> a(R,vector<char>(C));
char a[200][200];
int dx[]={
-1,1,0,0}; //上下左右
int dy[]={
0,0,-1,1};
Node jewelNode[11];
int visited[200][200][1 << 5 - 1]; //宝石数目最大11111
int bit1Count(int value) {
unsigned int count = 0;
while (value > 0) {
// until all bits are zero
if ((value & 1) == 1) // check lower bit
count++;
value >>= 1; // shift bits, removing lower bit
}
return count;
}
int bfs(Node *startNode,Node *endNode){
// 把startNode加入队列
visited[startNode->x][startNode->y][0] = 1; //置起点已经访问
queue<Node> q; // queue<Node*> q行不行?
q.push(*startNode); //起点入队 q.push(startNode)?
while(!q.empty()){
Node node=q.front();q.pop(); // 取队首元素,出队
// 对四个方向遍历
for(int i=0;i<4;i++){
int newx=node.x+dx[i];
int newy=node.y+dy[i];
// 越界或者已经访问则跳过--------------visited数组为什么是三维的: 包含了宝石的情况
if(newx