1. 程式人生 > >POJ1011 經典DFS+剪枝

POJ1011 經典DFS+剪枝

題意:

給你n個小棒碎片,要求還原原棒長,求最短原棒長

要點:

經典搜尋題,有很多剪枝,很早之前就想做一下,現在終於有水平可以做了,感覺水平還是有進步的,原來根本看不懂,現在好歹看的懂了,主要是各種剪枝實在是比較難想到。

從最大的一個碎片開始到碎片總和,一個個DFS是否為原棒長

剪枝:

1.原棒長必須是總數的因數

2.每次一開始從最大的碎片開始遍歷,如果每次一開始的無法搜尋成功直接剪掉,比如5,4,2,2要找6,用5遍歷找不到,那麼後面就不用算了,但要注意有可能一開始可以,後面出現失敗的情況,比如5,1,5,2,3找6,一開始5+1找到了,但後面重新搜尋時找不到,它剪枝剪掉的是每次重新尋找找不到的情況,所以要注意某些地方的位置不能顛倒,(這部分與剪枝4有部分重複,但最一開始的已經剪枝足夠多,所以無法替代)

3.相同的不用再算直接跳掉,比如5,5,4,4,第一個5搜尋不成功就不需要算第二個5了,同理5+4失敗就不需要算第二個4

4.如果已經拼出一個,下一個如果拼不出來,直接剪掉,比如5,1,3,1,4,第一次5+1=6滿足了,但第二次搜尋是搜不出6的,那麼後面不用算了,因為肯定都拼不出了

程式碼如下;

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int a[100];
bool vis[100];//標記陣列
int num, n, len;

int cmp(const void *a, const void *b)
{
	return *(int*)b - *(int*)a;//從大到小排列
}

bool dfs(int x,int pos,int l)
{
	if (x == num-1) //最後一個一定滿足不用考慮
		return true;
	bool sign = (l == 0 ? true : false);
	int i;
	for (i = pos + 1; i < n; i++) //注意這裡從pos+1開始
	{
		if (!vis[i])
		{
			if (l + a[i] == len)
			{
				vis[i] = true;
				if (dfs(x + 1, -1, 0))
					return true;
				vis[i] = false;
				return false;//已經拼出一個,後面如果失敗就全失敗直接剪掉
			}
			else if (l + a[i] < len)
			{
				vis[i] = true;
				if (dfs(x, i, l + a[i])) //這裡從i開始,因為前面已經-1了
					return true;
				vis[i] = false;//注意這個要放在這個位置,因為有可能第一次成功了,第二次從頭開始失敗	
				if (sign)
					return false; //判斷每次第一個能否成功,失敗後面就不用算了
				while (a[i] == a[i + 1])//如果失敗就跳過後面相同的
					i++; //注意因為這裡所以上面從pos+1開始
			}
		}
	}
	return false;
}

int main()
{
	while (scanf("%d", &n) != EOF, n)
	{
		int sum = 0;
		for (int i = 0; i < n; i++)
		{
			scanf("%d", &a[i]);
			sum += a[i];
		}
		qsort(a, n, sizeof(a[0]), cmp);
		for (len = a[0]; len <= sum; len++)
		{
			if (sum%len == 0)  //len肯定是sum的因數
			{
				num = sum / len;  //有num根原始棒子
				memset(vis, false, sizeof(vis));//每次都要先把標記陣列清零
				if (dfs(0, -1, 0))
				{
					printf("%d\n", len);
					break;//達到就直接跳出,保證最小
				}
			}
		}
	}
	return 0;
}




相關推薦

POJ1011 經典DFS+剪枝

題意: 給你n個小棒碎片,要求還原原棒長,求最短原棒長 要點: 經典搜尋題,有很多剪枝,很早之前就想做一下,現在終於有水平可以做了,感覺水平還是有進步的,原來根本看不懂,現在好歹看的懂了,主要是各種剪枝實在是比較難想到。 從最大的一個碎片開始到碎片總和,一個個DFS是否為原

poj1011 木棒 dfs+剪枝

目描述 喬治拿來一組等長的木棒,將它們隨機地砍斷,使得每一節木棍的長度都不超過50個長度單位。然後他又想把這些木棍恢復到為裁截前的狀態,但忘記了初始時有多少木棒以及木棒的初始長度。請你設計一個程式,幫助喬治計算木棒的可能最小長度。每一節木棍的長度都用大於零的整數表示。 In

HDU1455-經典DFS剪枝

George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original st

POJ1011 dfs剪枝

  B站上老師已經講的很清楚了,我掛個程式碼; B站:https://www.bilibili.com/video/av10046345/?p=18 #include<cstdio> #include<iostream> #include<algo

hdoj1455 poj1011 nyoj293 Sticks【DFS+剪枝

Sticks Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 128649 Accepted: 30149 Descrip

poj(1011)——Sticks(經典dfs+剪枝

題目的大致意思是: 現在有n根木棍,然後需要把它們拼成同樣長度的木棍,問滿足這個條件的最短的長度是多少? 想法嘛:那肯定是dfs把長度搜一遍就好,但問題的關鍵是這裡會超時。那麼就要用到剪枝的原理了。 以下部分是來自於pku的gw老師說噠 1)不要在同一個位置多次嘗試相同長度

poj1011——Sticks(dfs+剪枝

Description George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants

ZOJ 1457 Prime Ring Problem(dfs+剪枝

line alt sent math ica scanf 素數 n) div ?? Prime Ring Problem Time Limit: 10 Seconds Memory Limit: 32768 KB A ring is compose o

hdu2010(dfs+剪枝

nsis lines eno door open note isa 發現 fas Tempter of the Bone Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/

【UVa】Biggest Number(dfs+剪枝

scanf sin ret break puts 從大到小 如果 ssl ges 題目 題目 ? ? 分析 典型搜索,考慮剪枝。 統計一下聯通分量。 1、本位置能夠達到所有的點的數量加上本已有的點,還沒有之前的結果長,直接返回。 2、當本位置能夠達到所有的點的數量加上本

帶分數dfs+剪枝優化

for 優化 sed cin ble har 剪枝 lib stream #include<iostream>#include<cstdio>#include<cstdlib>#include<ctime>using name

POJ 1011 Sticks 【DFS 剪枝

解題思路 pro first mit contain earch smallest miss set 題目鏈接:http://poj.org/problem?id=1011 Sticks Time Limit: 1000MS Memory Limit: 1000

bzoj 1306: [CQOI2009]match循環賽【dfs+剪枝

clu include 記錄 != space () 要求 mat namespace 大力剪枝,最後洛谷上還開了o2才過…… 大概這樣剪枝: 1.搜索中,一個隊當前得分超過要求或者一個隊剩下的比賽場數全贏也達不到要求則return; 2.註意到如果平局,最總分的貢獻是2,

hdu - 1072(dfs剪枝

space sin else 題目 ios class pan using cstring 題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=1072 思路:深搜每一個節點,並且進行剪枝,記錄每一步上一次的s1,s2;如果之前走過

【2018多校Beautiful Now HDU - 6351】【dfs+剪枝

【連結】 http://acm.hdu.edu.cn/showproblem.php?pid=6351 【題意】 大意就是給你一個數n,求在最多k次得交換下,能夠得到的最大的數和最小得數是多少,且數不能有前導0 【分析】 數的大小不超過1e9,也就是9位數字。 顯然地,n個數

hdu2660---Accepted Necklace解題報告(DFS+剪枝)

                                      Accepted N

hdu1010---Tempter of the Bone解題報告(DFS + 剪枝)

                                     Tempter of the B

poj2676 Sudoku(數獨,dfs+剪枝

思路來源 https://blog.csdn.net/xiaozhuaixifu/article/details/12253507 題意 給定一個不完整9*9數獨, 未填部分用0表示, 恢復數獨,並列印 題解 在讀入的時候, 我們開幾個陣列, s

Hdu 6341 Problem.J Let Sudoku Rotate(dfs+剪枝

題意就是給你一個已經解完的數獨,但是他的某幾塊被逆時針旋轉過幾次,問你最小的旋轉次數。 當時比賽的時候,因為被題面嚇到了,以為是難題,就沒有仔細思考,現在看看,就是一道搜尋題,用bfs和dfs都可以過。 一開始想著如果用bfs的話,可能還要存下每旋轉一次的狀態,會顯得很繁瑣,就沒有選擇bfs

Hdu 6341 Problem J. Let Sudoku Rotate 暴力dfs+剪枝

Problem J. Let Sudoku Rotate Input file: standard input Output file: standard output Time limit: 2 seconds Memory l