洛谷p1120:明顯是搜尋題嘛
但是這資料增強不是一星半點吶
我們需要n多的剪枝
ps:需要先刪去超出50的木棍
首先我們可以想到列舉每個小木棍的長度來搜尋
但是直接列舉肯定會超時的 所以我們想到優化剪枝
因為要組成木棍肯定要從被砍開的木棍中的最大值開始列舉到所有木棍總和長(只有一根木棍被砍開)
然而這樣卻還不是最優的剪枝 因為每根原始小木棍的長度一樣 所以列舉長度的時候可以判斷是否被總和整除
而且我們只需要列舉到總和的一半即可 因為如果分成兩根或以下行不通的話 到最後只需要輸出總長就行(只有一根木棍)
因為短的可以組合得比長的更靈活 因此我們可以把木棍從大到小排序之後再選擇
進入dfs後我們需要判斷如果當前列舉的這根木棍還需要湊的長度為0且已經滿足:湊出的根數已經足夠(湊出長棍的根數=所有木棍的長度之和/原始長度)
當dfs失敗時 我們需要退出並換另外一根長度不同的木棍 因為一樣長度的可能有很多 所以時間浪費了 我們需要在進入dfs之前預處理出所有木棍下一根不同長度的編號
可以根據木棍長度的單調性來二分找出第乙個木棍長度不大於未拼長度rest
如果當前長棍剩餘的未拼長度等於當前木棍的長度或原始長度,繼續拼下去時卻失敗了,就直接回溯並改之前拼的木棍解釋:
當前長棍剩餘的未拼長度等於當前木棍的長度時,當前木棍明顯只能自組一根長棍,但繼續拼下去卻失敗,說明這根木棍不能自組?!這根木棍不自組就沒法用上了,所以不用搜更短的木棍了,直接回溯,改之前的木棍;當前長棍剩餘的未拼長度等於原始長度時,說明這根原來的長棍還一點沒拼,現在正在放入一根木棍。很明顯,這根木棍還沒有跟其它棍子拼接,如果現在拼下去能成功話,它肯定是能用上的,即自組或與其它還沒用的木棍拼接。但繼續拼下去卻失敗,說明現在這根木棍不能用上,無法完成拼接,所以直接回溯,改之前的木棍。
#include#includeview code#include
#include
using
namespace
std;
#define maxn 70
intn,k,minn,sum,c,num,len;
int mood[maxn],nex[maxn];//
nex是預處理編號
bool
vis[maxn],flag;
intcinn()
void write(int
x) bool cmp(int a,int
b)void dfs(int p,int last,int rest)//
p是當前已經拼倒第幾根 last是上一根用的編號 rest是還要多長
for(i=1;i<=n;i++)//
如果還沒湊齊 找一根還沒用過的當第一根要用的
if(!vis[i]) break
; vis[i]=1
; dfs(p+1,i,len-mood[i]);//
搜尋下一根
vis[i]=0
;
if(flag) return
; }
int l=last+1,r=n,mid;
while(l//
二分找編號
for(i=l;i<=n;i++)//
注意從第一根不同的編號開始而不是從1開始
}}void
read()
n--;
}n=k;
sort(
1+mood,1+mood+n,cmp);//
從大到小排序
minn=mood[1];//
木棍中的最大值是列舉長度的最小值
nex[n]=n;
for(int i=n-1;i>0;i--)//
預處理編號
}int
main()}}
write(sum);
//只有一根木棍
}
搜尋 P1120 小木棍
喬治有一些同樣長的小木棍,他把這些木棍隨意砍成幾段,直到每段的長都不超過5050。現在,他想把小木棍拼接成原來的樣子,但是卻忘記了自己開始時有多少根木棍和它們的長度。給出每段小木棍的長度,程式設計幫他找出原始木棍的最小可能長度。共二行。第一行為乙個單獨的整數n表示砍過以後的小木棍的總數,其中n 65...
洛谷P1120 小木棍 資料加強版 搜尋
玄學剪支,正好複習一下搜尋 感覺搜尋題的套路就是先把整體框架打出來,然後再一步一步優化剪枝 1.從maxv到sumv 2列舉長度 想一想,為什麼 2.開乙個桶,從大到小開始列舉 3.在搜尋中,列舉到長度為x的木棍,則下一步也從x開始列舉 4.如果當前長度為0或target卻無解則break掉,很玄學...
洛谷P1120 小木棍(公升級版)
傳送門啦 一道經典的搜尋剪枝題,不廢話,步入正題。一 輸入時手動過濾不合法的情況 二 很明顯我們要列舉把哪些棍子拼接成原來的長棍,而原始長度 原來的長棍的長度 都相等,因此我們可以在 dfs 外圍列舉拼接後的每根長棍的長度。那列舉什麼範圍呢?其長度至少是最長的一根木棍,此時最長的這根木棍恰好單獨組成...