POJ 2362 Square【題解報告|定序DFS】

題目鏈接

題目大意

給你M根長度可能不同的棍子,問你用着M根棍子能否拼成一個正方形.

思路分析

首先將M根棍子的總長sum求出,sum%4必須==0且任意一個棍子的長度<=sum/4.

用vis[i]數組表示當前第i根棍子是否被使用了.

然後用dfs來判斷能否構成正方形的四邊即可.其中
bool dfs(int num, int len, int j)表示當前正在構造第num根棍子且當前棍子已經湊到了len的長度,下一次從第j個木棍開始搜索。這裏注意網上很多解法都是對棍子排序了的,其實不用排序也行.因爲我們用到的是定序剪枝,只要棍子的順序固定就行.

源代碼中最重要的剪枝是dfs函數中的下一次開始begin位置的記錄,假設我們當前這步與下一步都是在構造同一條邊,那麼我們下次搜索所有棍子只需要從begin+1位置開始找即可,不用從0開始選。爲什麼?

假設我們當前剛設置完vis[5]=1,表示第5根棍子我們在還是left長度的時候用了,現在我們還是left-len[5]長度的時候要不要去用len[2]來嘗試配對一下?不用,肯定無解.因爲搜索的時候我們是先找的len[2]的,如果len[2]+len[5]+….有一個可行解(可以配對成當前cnt邊)的話,我們之前肯定已經找到了且推出了dfs這個函數.但是現在明顯我們還沒找到,所以len[2]+len[5]+…不可能是一個可行解,所以直接從5後面的位置繼續找即可.如果還不能理解,就把本題想象成我們只需要配對一條正方形的邊,不用配4邊了.


//164K	79MS
#define inf 0x3f3f3f3f
#define vec vector<int>
#define P pair<int,int>
#define ll long long
#define MAX 25

int T, n, a[MAX], vis[MAX], sum, ma;

//目前在拼湊num個木棍,第num個長度爲0,上一個用了j號木棍
bool dfs(int num, int len, int j) {
	if (num == 5)return true;

	for (int i = j + 1; i < n; i++) {
		if (vis[i])continue;
		if (len + a[i] == sum / 4) {
			vis[i] = 1;
			if (dfs(num + 1, 0, 0))return true;
			vis[i] = 0;
		}
		else if (len + a[i] < sum / 4) {
			vis[i] = 1;
			if (dfs(num, len + a[i], i))return true;
			vis[i] = 0;
		}
	}
	return false;
}

int main() {
	scanf("%d", &T);
	while (T--) {
		scanf("%d", &n);
		sum = 0; ma = 0;
		for (int i = 0; i < n; i++)
			scanf("%d", &a[i]), sum += a[i], ma = max(ma, a[i]);

		if (ma > sum / 4 || sum % 4 != 0) { 
			cout << "no" << endl; 
			continue;
		}
		memset(vis, 0, sizeof(vis));
		if (dfs(1, 0, -1))cout << "yes" << endl;
		else cout << "no" << endl;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章