Poj 1708 Game【題解報告|啓發式DFS】

題目鏈接

題目大意

給出N個點(不超過100個),每個點有一個顏色(顏色標號不超過100),有一些點的顏色可以相同。給出M條有向邊,這些邊也有一個顏色。給出兩個棋子的初始點L,K,終點Q,問兩個棋子中的任意一個是否可以移動到Q,如果可以,輸出移動的最小步數。移動時遵循以下規則:

1.一個棋子可以移動到下一個點需要滿足:經過的邊的顏色與另一個棋子所在點的顏色相同;

2.只能沿着有向邊的方向;

3.兩個棋子不能同時移動到同一個點;

4.移動次序任意,沒有必要交替進行;

5.其中一個棋子到達Q點時遊戲結束。

思路分析

拿到題比較容易想到要搜索,但是怎麼搜是一個問題,因爲有兩個點同時可以動,而且一個點能否前進受到另一個點的掣肘。如何建模這件事情是這道題的難點,而且搜索的圖中,我們一定要避免重複狀態的出現,而在這裏,我們不能簡單的訪問過一個點就給他打上標記,因爲即使在同一個點,兩個pawn的位置不同得到的結果也是不同的。

關鍵在於pawn的位置,所以我們不妨將pawn的位置作爲搜索的狀態,

struct step {//dfs所用的狀態
	int v1, v2, cnt;//第一個pawn和第二個pawn的狀態,以及所用的步數
	step(int a = 0, int b = 0, int c = 0) { v1 = a, v2 = b, cnt = c; }
};

那麼重複狀態就定義爲,v1,v2重複。如果此時我們訪問到一個點n,那麼我們有兩種前進的方式,一種是第一個pawn前進,一種是第二個pawn前進,分別對這兩種方式進行搜索,保證題目中的條件得到滿足

#define ll long long
#define vec vector<int>
#define inf 0x3f3f3f3f
#define P pair<string,string>
#define MAX 105

struct edge {//邊
	int to, c;
	edge(int a = 0, int b = 0) { to = a, c = b; }
};
struct step {//dfs所用的狀態
	int v1, v2, cnt;//第一個pawn和第二個pawn的狀態,以及所用的步數
	step(int a = 0, int b = 0, int c = 0) { v1 = a, v2 = b, cnt = c; }
};

vector<edge> G[MAX];//圖
int N, L, K, Q, col[MAX], A, B, C, M, vis[MAX][MAX], res;

void bfs() {
	memset(vis, 0, sizeof(vis));
	vis[L][K] = 1; queue<step> q; q.push(step(L, K, 0));

	while (!q.empty()) {
		int v1 = q.front().v1, v2 = q.front().v2, num = q.front().cnt;
		q.pop();
		if ((v1 == Q || v2 == Q) && num < res)res = num;//更新答案

		//第一個點向前搜索
		for (int i = 0; i < G[v1].size(); i++) {
			edge e = G[v1][i];
			//該狀態未曾訪問,邊的顏色與v2相等,不會到同一個點中
			if (!vis[e.to][v2] && e.c == col[v2] && e.to != v2) {
				vis[e.to][v2] = 1;
				q.push(step(e.to, v2, num + 1));
			}
		}

		//第二個點向前搜索
		for (int i = 0; i < G[v2].size(); i++) {
			edge e = G[v2][i];
			if (!vis[v1][e.to] && e.c == col[v1] && e.to != v1) {
				vis[v1][e.to] = 1;
				q.push(step(v1, e.to, num + 1));
			}
		}
	}
}

int main() {
	while (scanf("%d %d %d %d", &N, &L, &K, &Q) != EOF) {
		for (int i = 1; i <= N; i++)scanf("%d", &col[i]);
		scanf("%d", &M);
		for (int i = 0; i < M; i++) {
			scanf("%d %d %d", &A, &B, &C);
			G[A].push_back(edge(B, C));
		}
		
		res = inf; bfs();
		if (res == inf)printf("NO\n");
		else printf("YES\n%d\n", res);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章