7.5 The Morning after Halloween

本题主要是存储的问题,在存储上笔者原先的代码占用了大量的内存空间
这边笔者采用暴力的思想直接硬开所有情况的16^6的数组来存储该问题,当然这在时间上是十分浪费的,因为初始化实在太慢了,剩下的就是状态转移,以及隐式图的相关思路

点击查看笔者代码
#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;

constexpr int maxl = 16, maxn = 16777216+5, base = 4, debase = 15;
int w, h, n, des, sta, st[maxl/4][2], ed[maxl/4][2], G[maxl][maxl];
int dx[5] = {0, 0, 0, 1, -1};
int dy[5] = {0, 1, -1, 0, 0};
bool vis[maxn];

struct Node{
  int value, costed;
  Node(int value = 0, int costed = 0) : value(value), costed(costed) {}
};

bool getD() {
  cin >> w >> h >> n;
  if(!w) return false;
  int cnt = 0, buf[26][2][2], sign[26]; memset(sign, 0, sizeof(sign));
  string line; getline(cin, line); memset(G, 1, sizeof(G));
  for(int i = 0; i < h; i++) {
    getline(cin, line); 
	int len = line.length();
    for(int j = 0; j < len; j++) {
      if(line[j] == ' ') G[i][j] = 1;
	  else if(line[j] == '#') G[i][j] = 0;
	  else {
	  	G[i][j] = 1; 
	  	if(isupper(line[j])) { buf[line[j]-'A'][0][0] = i; buf[line[j]-'A'][0][1] = j; sign[line[j]-'A'] = 1; }
	  	else { buf[line[j]-'a'][1][0] = i; buf[line[j]-'a'][1][1] = j; sign[line[j]-'a'] = 1; }
	  } 
	}
  }
  memset(vis, 0, sizeof(vis));
  for(int i = 0; i < 26; i++) 
  	if(sign[i]) {
	  st[cnt][0] = buf[i][1][0]; st[cnt][1] = buf[i][1][1];
	  ed[cnt][0] = buf[i][0][0]; ed[cnt++][1] = buf[i][0][1];
	}
  return true;
}

int toInt(int (&arr)[4][2]) {
  int temp = 0;
  for(int i = 0; i < n; i++) {
  	temp = (((temp<<4)|arr[i][0]) << 4) | arr[i][1];
  }
  return temp;
}

#ifdef LOCAL
#include<algorithm>
void output(int num) {
  string line;
  do {
  	line += num%2+'0';
  	num /= 2;
  } while(num);
  reverse(line.begin(), line.end());
  cout << line << endl;
}
#endif

void output(int (&arr)[4][2]) {
  for(int i = 0; i < n; i++) cout << arr[i][0] << " " << arr[i][1] << " ";
  cout << endl;
}

void toPos(int num, int (&arr)[4][2]) {
  for(int i = n-1; i >= 0; i--) {
  	arr[i][1] = num & debase;
  	num = num >> base;
  	arr[i][0] = num & debase;
  	num = num >> base;
  }
}

void findPath(vector<int> &v, int cur, int (&npos)[4][2], int (&pos)[4][2]) {
  if(cur == n) { 
    for(int i = 0; i < n; i++) 
      for(int j = i+1; j < n; j++) 
      	if((npos[i][0] == npos[j][0] && npos[i][1] == npos[j][1]) || (npos[i][0]==pos[j][0] && npos[i][1]==pos[j][1] && npos[j][0]==pos[i][0] && npos[j][1]==pos[i][1])) return;
    int temp = toInt(npos);  
	if(!vis[temp]) { 
	  vis[temp] = true; 
	  v.push_back(temp); 
	}
	return; 
  }
  for(int i = 0; i < 5; i++) {
  	int nx = pos[cur][0] + dx[i], ny = pos[cur][1] + dy[i];
  	if(nx >= 0 && nx < h && ny >= 0 && ny < w && G[nx][ny]) {
  	  npos[cur][0] = nx; npos[cur][1] = ny;
	  findPath(v, cur+1, npos, pos);	
	}
  }
}

int main() {
  while(getD()) {
    sta = toInt(st);
    des = toInt(ed); 
    queue<Node> q;
    q.push(Node(sta, 0));
    int ans = 0;
    vis[sta] = true;
	while(!q.empty()) { 
      Node temp = q.front(); q.pop();
      if(temp.value == des) { ans = temp.costed; break; }
	  int pos[4][2], npos[4][2];
	  toPos(temp.value, pos);
      vector<int> v;
      findPath(v, 0, npos, pos);
      for(int i = 0; i < v.size(); i++) q.push(Node(v[i], temp.costed+1));
	}
	cout << ans << endl;
  }
  return 0;
} 

注意,对于这种转移代价高的,我们要想办法减少转移代价,因为其实题目中有很多障碍格,因此并不是所有四个方向都能移动,因此可以把所有空格提出来建立一张图,而不是每次临时判断5中方法是否合法
其次,是换一个算法,例如双向广度优先搜索,双向BFS首先需要直到起点和终点,然后就可以正着搜索一层,反着搜索一层,这样交替下去,直到两层中出现相同的状态
A算法也是挺好的,不过此时就是使用优先队列,A算法最重要的就是估值函数的选取,
f(x) = h(x) + g(x)
h(x):是当前到x所需要花费的代价
g(x):启发式信息,根据x推断到达终点所需要花费的代价,一个好的启发式算法可以大大减少需要搜索遍历到的点

posted @   banyanrong  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示