# DFS# Backtracking# Array

b841 - 104北二5.骨牌遊戲

🔗 前往 ZeroJudge 原題

題目描述

題目要求在一個 H x W 的棋盤上,找出可以配對的骨牌的最大數量。骨牌由兩個數值相同且相鄰的格子組成,相鄰指的是水平或垂直方向。

解題思路

這題可以使用深度優先搜尋 (DFS) 或回溯法來解決。基本思路是遍歷棋盤,如果找到可以配對的骨牌,則將它們標記為已使用,並遞迴地尋找剩餘棋盤上的骨牌。在遞迴的每一步,記錄目前找到的骨牌數量,並更新最大值。回溯時,將標記為已使用的骨牌恢復原狀,以便探索其他可能的配對方案。

程式碼首先讀取棋盤的尺寸和數值。然後,它遍歷棋盤的每個格子,檢查是否可以形成水平或垂直的骨牌。如果可以,則將骨牌標記為已使用,並遞迴地尋找剩餘棋盤上的骨牌。在遞迴過程中,更新最大骨牌數量。最後,回溯時將骨牌恢復原狀,以便探索其他可能的配對方案。

複雜度分析

  • 時間複雜度: O(2^(H*W)),在最壞情況下,需要嘗試所有可能的骨牌配對組合。
  • 空間複雜度: O(H*W),主要用於儲存棋盤和遞迴呼叫堆疊。

程式碼

#include <iostream>
using namespace std;
int n,m,a[10][10],ans;
bool jr(int x,int y,int t){
	if(a[x][y]==0)return 0;
	if(t){// ->
		if(y>=m-1)return 0;
		if(a[x][y+1]==0)return 0;
		if(a[x][y]!=a[x][y+1])return 0;
		return 1;
	}
	else{
		if(x>=n-1)return 0;
		if(a[x+1][y]==0)return 0;
		if(a[x][y]!=a[x+1][y])return 0;
		return 1;
	}
}
void dfs(int x,int y,int s){
	ans=max(s,ans);
	int st=y;
	for(int i=max(x-1,0);i<n;++i){
		for(int j=st;j<m;++j){
			if(jr(i,j,0)){
				int tmp=a[i][j];
				a[i][j]=a[i+1][j]=0;
				dfs(i,j+1,s+1);
				a[i][j]=a[i+1][j]=tmp;
			}
			else if(jr(i,j,1)){
				int tmp=a[i][j];
				a[i][j]=a[i][j+1]=0;
				dfs(i,j+1,s+1);
				a[i][j]=a[i][j+1]=tmp;
			}
		}
		st=0;
	}
}
int main(){
	cin.tie(0); ios::sync_with_stdio(false);
	cin >> n >> m;
	for(int i=0;i<n;++i){
		for(int j=0;j<m;++j){
			cin >> a[i][j];
		}
	}
	for(int i=0;i<n;++i){
		for(int j=0;j<m;++j){
			if(jr(i,j,0)){
				int tmp=a[i][j];
				a[i][j]=a[i+1][j]=0;
				dfs(i,j+1,1);
				a[i][j]=a[i+1][j]=tmp;
			}
			else if(jr(i,j,1)){
				int tmp=a[i][j];
				a[i][j]=a[i][j+1]=0;
				dfs(i,j+1,1);
				a[i][j]=a[i][j+1]=tmp;
			}
		}
	}
	cout << ans;
}

Discussion