1. 程式人生 > >【 OJ 】 HDOJ1044 18年12月3日19:00 [ 38 ]

【 OJ 】 HDOJ1044 18年12月3日19:00 [ 38 ]

本題基本思路大致相同,先用BFS算出所有節點對的最短距離,然後用DFS遞迴所有情況得出最大結果(合理剪枝)

思路還是很簡單的,但是很遺憾此題沒有被AC,WA了,不清楚哪裡錯了...估計啥格式啥的...細節吧....

程式碼僅供參考吧...ummm

# include<iostream>
#include<queue>
# define NMAX 1000001
using namespace std;
struct Point {
	int x, y, step;
	bool check(int X, int Y) {
		if ((x >= 0 && x < X) && (0 <= y&&y < Y))
			return true;
		return false;
	}
};
char Map[50][50];
bool MapVisit[50][50];//用於判斷點是否被訪問
Point P[12];//記錄12個位置 10個珠寶+S+End(起點終點)
int dir[4][2] = { { 0,1 },{ 1,0 },{ 0,-1 },{ -1,0 } };//東南西北
int M_[12][12];//記錄12點之間的最短路徑
bool  JewelVisit[12];//訪問表 0 起點 1 終點
int V[12] = { 0,0 };//珠寶價值 0 起點 1 終點 
int T, L, W, H, M;//執行次數  列 行  限制時間 珠寶
int Stack[12], Stack_index;//用於記錄DFS探索的最多寶物
bool Flag;//用於判斷是否結束DFS
void BFS(void) {
	queue<Point>q;
	Point p, tp;
	int i, j, k;
	for (i = 0; i < M + 2; i++) {
		memset(MapVisit, 0, sizeof(MapVisit));//初始化地圖訪問表
		while (!q.empty())q.pop();//初始化佇列
		if (i == 1)continue;//終點沒必要計算
		q.push(P[i]);//起點入隊
		while (!q.empty()) {
			tp = p = q.front();//取對頭元素
			q.pop();//出隊
			for (k = 0; k < 4; k++, tp = p) {//四向檢查
				tp.x += dir[k][0]; tp.y += dir[k][1];//向 dir【i】移動
				if (tp.check(H, W)) {//合法可走
					if (Map[tp.x][tp.y] != '*' && !MapVisit[tp.x][tp.y]) {
						tp.step++; q.push(tp); MapVisit[tp.x][tp.y] = true;
						if ('A' <= Map[tp.x][tp.y] && Map[tp.x][tp.y] <= 'Z') {//遇到了珠寶
							int temp = Map[tp.x][tp.y] - 'A' + 2;
							M_[i][temp] = tp.step;//記錄當前BFS的第 i 個珠寶到探索到的第 temp 個珠寶最短路徑
						}
						if (Map[tp.x][tp.y] == '<') 	M_[i][1] = tp.step;//0 起點 1 終點
					}
				}
			}
		}
	}//初始化所有珠寶之間的最短距離
}
void DFS(int Curent_Jewel, int Curent_Limit) {
	if (!JewelVisit[0]) {
		JewelVisit[0] = true;
		Stack[Stack_index++] = 0;// 0 起點 1 終點 2-12 代表寶物 ABC.....
	}
	for (int i = M + 1; i >0; i--) {//從第 12 個寶物開始探索直到終點
		if (JewelVisit[i])continue;//該寶物被探索就下一個
		if (M_[Curent_Jewel][i] <= Curent_Limit) {//剩餘時間還能到達第 i 個寶物
			if (i == 1) {
				Flag = true;//找到了最大路徑
				return;
			}
			if (M_[i][1] < Curent_Limit - M_[Curent_Jewel][i])continue;//去拿了此寶物,但是到達終點的時間是不夠的
			Stack[Stack_index++] = i;//第 i 個寶物入棧
			JewelVisit[i] = true;
			DFS(i, Curent_Limit - M_[Curent_Jewel][i]);//現在當前寶物變成 i 剩餘時間為當前剩餘時間減去當前寶物到 i寶物的時間開銷 
			if (Flag)return;//已經找到最大值
			Stack_index--;
			JewelVisit[i] = false;
		}
	}
}
int main(void) {
	cin >> T;
	int time = 0;
	int Total_V;
	while (T--) {
		int i, j;
		//初始化區域
		//----------------------------------------
		memset(JewelVisit, 0, sizeof(JewelVisit));
		Stack_index = 0;//初始化Stack_index
		Flag = false;//初始化Flag
		for (i = 0; i < 12; ++i)
			for (j = 0; j < 12; j++)
				M_[i][j] = NMAX;//初始化M_表
								//-----------------------------------------
		cin >> W >> H >> L >> M;//錄入基本資訊
		for (i = 2; i < M + 2; i++) {
			cin >> V[i];
		}//錄入珠寶價值
		for (i = 0; i < H; i++) {
			for (j = 0; j < W; j++) {
				cin >> Map[i][j];
				if ('A' <= Map[i][j] && Map[i][j] <= 'Z') {
					int k = Map[i][j] - 'A' + 2;
					P[k].step = 0; P[k].x = i; P[k].y = j;
				}
				if (Map[i][j] == '@') {
					P[0].x = i; P[0].y = j; P[0].step = 0;
				}//錄入起點資訊
				if (Map[i][j] == '<') {
					P[1].x = i; P[1].y = j; P[1].step = 0;
				}//錄入終點資訊
			}
		}//錄入地圖資訊
		BFS();//廣搜出所有結點對最短距離
		DFS(0, L);//深搜出最大結果
		Total_V = 0;
		for (i = 0; i < Stack_index; i++) {
			Total_V += V[Stack[i]];
		}
		if (M_[0][1] > L)
			cout << "Impossible" << endl;
		else
			cout << "Case " << ++time << ":" << endl << "The best score is " << Total_V << "." << endl;
		if (T)
			cout << endl;
	}
	system("pause");
	return 0;
}