1. 程式人生 > >【 OJ 】 HDOJ1026 18年11月10日22:22 [ 25 ]

【 OJ 】 HDOJ1026 18年11月10日22:22 [ 25 ]

這題  Memory Limit Exceeded  Memory Limit:32768 K本題在測試機上是35343K

這題如果想AC可以不用看本人的話了....因為超了記憶體,如果只是想了解思想,強烈推薦,感覺還是很不錯滴~自賣自誇下

這題我用了visit 來記錄了所有能到達結點的最短路徑數(並不需要全做,只要到了目的地就可以retun結束)【想了一下這句話也是錯了,原因很簡單,雖然正常來說在佇列中先被訪問的一定是比較近的點,但是由於此題有n怪物,所以不一定是最近的,有可能目的地確實先被訪問了,但它其實可以被鬆弛操作,意思它途徑了n怪物點,因此它不是最近的路徑,此時return了答案可能會不對】

因此超了記憶體,開始思路有點亂,又想通過路徑數來找找路徑,又想用方向陣列來指向

找路徑,又想通過標記方向陣列  -> 或者  <-  來找路徑 後來用數字模擬方向

用dri 記錄所有點到達map[0][0]的路徑,逆推 1 ( -> )東 2 ( v )南 3 ( <- ) 西 4 ( ^ )北

重理思路:

之前說不需要做最短路徑數是不對的,後來想了想,如果沒有最短路徑數那麼就沒辦法確定是否做鬆弛操作,沒法確定是否做鬆弛操作就沒法確定是否修改指向.... 因此此題超記憶體.....當遇到目的地後直接return 剩下點都不用計算了,可能會....節省點記憶體


    1: 首先思想BFS用佇列實現
    2 :  路徑的最後輸出又棧實現【可由陣列代替】
    從(0,0)開始入隊,讀取到一個當前節點 p 就遍歷他的四周所有可行點,如果【第一次發現這個節點】,將這個節點入隊,然後標記路徑長,為當前 p 節點路徑+1,如果是 n,
    那麼就再 +n (注 * 前面+1必做),如果遍歷發現這個節點【不第一次發現這個節點】,那麼就看能否鬆弛【鬆弛操作】,就是當前 p 節點+1是否小於這個節點目前的路徑數,如果小於,那麼這個節點還需要入佇列,並且修改最短路徑

如果不小於說明不用做  ---------以上BFS可以求出所有可到達節點的最短路徑長度

(其實通過所有最短路徑數也是可以逆推出路徑的,從目的結點開始每次少1步就是,遇到n,減去(n+1)即可)

因為路徑數為6的結點周圍可能3個都是路徑數為7的,但是7的周圍肯定只有1個,因此可以逆推,但是不方便,

所以加上指向肯定會更加方便找
    因此本題思路來源於 BFS 兩個串的最長共同子序列 (在陣列中可以標記最短路徑長度也可以給出路徑的方向)如果有疑問可以看 演算法導論的 BFS 例題講解

    下面的所有操作其實是加在上述的求最短路徑數步驟中的,讀者自行體會
    依舊從(0,0)開始入隊遍歷周圍每一個可行結點,如果第一次發現,將那個結點 標記下方向

【例如 當前點 p為 0,0發現向東走 0,1可以走,那麼0,1點就標記為3(西)說明(0,1)向西走可以回到當前結點-這樣從目的結點可以通過指向一路走到起始位置】

如果不是第一次,還是看是否能鬆弛,如果能鬆弛就修改指向
 直至整個地圖遍歷結束

//下面的函式用來輸出BFS後地圖的所有能到達點的最短路徑

for (i = 0; i < N; i++) {
	for (j = 0; j < M; ++j) {
		if (visit[i][j] == IFMAX)
			cout << "X ";
		else
			cout << visit[i][j]<<" ";
	}
	cout << endl;
}//鬆弛後所有的地圖資訊已經清晰

//下面的函式用來輸出地圖的方向 1東 2 南 3西 4北 從 map[N-1][M-1]看方向到map[0][0]

for (i = 0; i < N; i++) {
	for (j = 0; j < M; ++j) {
		if (i == 0 && j == 0)
			cout << "S";
		else {
			if (dri[i][j] == 0)
				cout << "X";
			else
				cout << dri[i][j];
		}
}
cout << endl;
}

//下面是原始碼 

# include <iostream>
# include <queue>
# include <stack>
#define IFMAX 200
using namespace std;
int N, M;//行 列
struct Path {
	int x;
	int y;
	int p;
}p;
int visit[102][102];//題意 最大100*100
int dri[102][102];
char map[102][102];
int d[4][2] = { { 0,1 },{ 1, 0 },{ 0, -1 },{ -1, 0 } };
int min(int a, int b) {
	return a < b ? a : b;
}
void PUSH(int dir_, queue<Path>&q) {
	if (map[p.x][p.y] == '.') {//正常步子
		if (p.p + 1<visit[p.x][p.y]) {//發現能被鬆弛就入棧
			visit[p.x][p.y] = ++p.p;
			q.push(p);
			dri[p.x][p.y] = dir_;
		}
	}
	else {//為n 
		if (visit[p.x][p.y] == IFMAX) {
			q.push(p);//第一次訪問入隊
			dri[p.x][p.y] = dir_;
		}
		visit[p.x][p.y] = min((p.p + 1 + (map[p.x][p.y] - '0')), visit[p.x][p.y]);//鬆弛操作是不是第一次入隊都要做
		if ((p.p + 1 + (map[p.x][p.y] - '0')) < visit[p.x][p.y]) {//可以被鬆弛
			q.push(p);//可以鬆弛入隊
			dri[p.x][p.y] = dir_;
		}
	}
}
void check(queue<Path>&q) {
	//地圖資訊  X .  n  
	for (int i = 1; i < 5; ++i) {//東 南 西 北
		p.x += d[i-1][0];
		p.y += d[i-1][1];
		if ((p.x >= 0 && p.x < N) && (0 <= p.y&&p.y < M) && map[p.x][p.y] != 'X') {//東
			PUSH((((i+1)%4)+1), q);
		}
		p = q.front();//回溯原來位置
	}
}
void BFS(void) {
	queue<Path> q;
	p.x = p.y = p.p = 0;
	q.push(p);
	while (!q.empty()) {
		p = q.front();
		p.p = visit[p.x][p.y];
		check(q);//檢查四周,將可入隊的入隊
		q.pop();//將遍歷過的出隊
	}//遍歷完所有地圖
}
void TravelStack(stack<Path> &s) {
	int n, num = 0;
	Path pi;
	p = s.top();
	s.pop();
	while (!s.empty()) {
		pi = p;
		if (map[pi.x][pi.y] != '.') {
			n = map[pi.x][pi.y] - '0';
			for (int i = 0; i < n; ++i) {
				cout << ++num << "s:FIGHT AT(" << pi.x << ", " << pi.y << ")" << endl;
			}
		}
		p = s.top();
		s.pop();
		cout << ++num << "s:(" << pi.x << ", " << pi.y << ")->(" << p.x << ", " << p.y << ")" << endl;
	}
	cout << "FINISH" << endl;
}
void TrevealPath(void) {
	p.x = N - 1;
	p.y = M - 1;//終點標記起點位置
	p.p = visit[N - 1][M - 1];
	if (p.p == IFMAX) {//暗示了路徑是不通的,所以呼叫上帝
		cout << "God please help our poor hero.\nFINISH" << endl;
		return;
	}
	stack<Path> s;
	s.push(p);//起始點入棧
	while (p.x != 0 || p.y != 0) {//終止位置不為(0,0)就迴圈
		for (int i = 1; i < 5; ++i) {
			if (dri[p.x][p.y] == i) {
				p.x += d[i - 1][0];
				p.y += d[i - 1][1];
				s.push(p);
				break;
			}
		}
	}
	cout << "It takes " << visit[N - 1][M - 1] << " seconds to reach the target position, let me show you the way." << endl;
	TravelStack(s);
}
int main(void) {
	while (cin >> N >> M) {// N 行 M 列
		int i, j;
		for (i = 0; i < N; i++) {
			for (j = 0; j < M; ++j) {
				cin >> map[i][j];
				visit[i][j] = IFMAX;
				dri[i][j] = 0;
			}
		}//錄入地圖資訊
		visit[0][0] = 0;
		BFS();//BFS map資訊
		TrevealPath();
	}
	system("pause");
	return 0;
}