# DFS# Backtracking# State Space Search

e527 - 106 彰雲嘉區複賽 - Q7 無刻度容器倒水問題

🔗 前往 ZeroJudge 原題

題目描述

題目要求找出使用兩個無刻度容器,容量分別為 x 和 y,量出 z 升水所需的最少步驟數。步驟包括將容器裝滿、倒空或將一個容器的水倒入另一個容器。如果無法量出 z 升水,則輸出 -1。

解題思路

本題可以使用深度優先搜尋 (DFS) 來解決。狀態空間由兩個容器中的水量表示,即 (x, y)。每次 DFS 嘗試所有可能的動作:

  1. 將 x 容器裝滿。
  2. 將 y 容器裝滿。
  3. 將 x 容器倒空。
  4. 將 y 容器倒空。
  5. 將 x 容器的水倒入 y 容器,直到 y 容器滿或 x 容器空。
  6. 將 y 容器的水倒入 x 容器,直到 x 容器滿或 y 容器空。

DFS 從初始狀態 (0, 0) 開始,並記錄每個狀態的步驟數。如果找到一個狀態,其中一個容器中的水量等於 z,則更新最小步驟數。為了避免無限循環,我們使用一個 visited 陣列來記錄已經訪問過的狀態。

複雜度分析

  • 時間複雜度: O(x * y * (x + y))。最壞情況下,DFS 可能需要訪問所有可能的狀態,狀態數量為 x * y。每次 DFS 呼叫需要 O(x + y) 的時間來執行所有可能的動作。
  • 空間複雜度: O(x * y)。visited 陣列的大小為 x * y,用於儲存已訪問的狀態。遞迴深度最壞情況下為 x + y。

程式碼

#include <bits/stdc++.h>
using namespace std;
int t,xx,yy,z,a[1026][1026],ans;
void dfs(int x,int y,int ct){
	if(a[x][y]<=ct||ct>=ans)return;
	a[x][y]=ct;
	if(x==z||y==z){
		ans=ct;
		return;
	}
	if(x)dfs(0,y,ct+1);
	if(y)dfs(x,0,ct+1);
	if(x!=xx){
		dfs(xx,y,ct+1);
		if(y){
			if(x+y>xx){
				dfs(xx,y-xx+x,ct+1);
			}
			else{
				dfs(x+y,0,ct+1);
			}
		}
	}
	if(y!=yy){
		dfs(x,yy,ct+1);
		if(x){
			if(x+y>yy){
				dfs(x-yy+y,yy,ct+1);
			}
			else{
				dfs(0,x+y,ct+1);
			}
		}
	}
	
}
int main(){
	cin >> t;
	while(t--){
		ans=1001;
		cin >> xx >> yy >> z;
		memset(a,0x3f,sizeof(a));
		dfs(xx,yy,0);
		if(ans>1000)
			cout << "-1\n";
		else
			cout << ans << "\n";
	}
}

Discussion