能想到是那種列舉子集的動態規劃,結果寫著寫著成了模擬了= =。
s是位向量,代表著巧克力的集合。
dp[s]是乙個vector,裡面裝著巧克力集合s能拼出的長方形。模擬轉移方程就是列舉s的子集s0,s1,然後拼出乙個長方形,然後排序去重。。。果斷超時。
其實這種o不ok的問題,狀態轉移方程都是一旦有一種決策ok,那就ok。
問題在於狀態是啥,轉移方程是啥。
很容易想到dp[s][x][y]代表集合s的巧克力拼成x*y的長方形可不可以。每一種決策就是列舉s得子集s0,以及割法1<=x0
這個時間複雜度是遠遠不能承受的。
我們發現,狀態定義了很多,狀態轉移也定義了很多,但是事實上大量的空間被浪費了,因為大量的狀態是不會得到的,大量的轉移也是失敗的。這就提供了優化的契機。
因此我們需要把狀態定義得緊湊一點,然後用記憶化搜尋。
觀察狀態,發現集合s巧克力的總面積很可能不等於x*y。所以才被浪費了大量的空間。
我們不如讓每乙個被搜尋的狀態集合s都等於x*y。那麼我們就可以減少一維的空間,因為完全可以通過s與x計算出y。然後我們還發現x和y是對稱的,不如令x
首先s的和同時是x和y的倍數。
轉移方程就是列舉s的子集s0,補集s1。
如果s0的和是x的倍數,那麼s1的和就也是x的倍數,那麼說明能對y切一刀,分成兩個子狀態。
y同理。
然後就看看有沒有合法的子狀態咯,因為儘管這樣都還是有大量的空間和決策被浪費,所以用記憶化搜尋。
總時間複雜度為o(x3^n)因為記憶化搜尋,很多狀態達不到,所以實際運算量遠小於o(x3^n)。
** #include#define maxn 15
#define maxx 110
#define maxs (1<<15)
using namespace std;
int n,x,y,kase,all;
int a[maxn],d[maxs][maxx],sum[maxs];
int bitcnt(int x)
bool dp(int s,int x)
return ans=0;
}bool print()
int main()
{ while(scanf("%d",&n)==1&&n)
{scanf("%d %d",&x,&y);
for(int i=0;i
動態規劃 記憶化搜尋
記憶化搜尋顧名思義是在搜尋的過程中通過記錄搜尋的中間狀態從而達到減少重複搜尋的方法,通常用在搜尋樹 現重複子節點的情況。例題 滑雪 給定乙個r行c列的矩陣,表示乙個矩形網格滑雪場。矩陣中第 i 行第 j 列的點表示滑雪場的第 i 行第 j 列區域的高度。乙個人從滑雪場中的某個區域內出發,每次可以向上...
巧克力棒(記憶化搜尋)
巧克力棒 總時間限制 2000ms 記憶體限制 65536kb 描述 有乙個n m 1 n,m 30 的矩形巧克力,每一次都可以橫向或者縱向切,且每次切的花費為所切邊長的平方。問最後得到面積為k個單位巧克力 k min n m,50 的最小花費是多少?舉例 有乙個2 3的矩形巧克力,你可以橫向切,就...
動態規劃之記憶化搜尋
一.動態規劃 動態規劃 dynamic programming 與 分治思想 有些相似,都是利用將問題分 為子問題,並通過合併子問題的解來獲得整個問題的解。於 分治 的不同之處在 於,對於乙個相同的子問題動態規劃演算法不會計算第二次,其實現原理是將每乙個計算過的子問題的值儲存在乙個表中。二.記憶化搜...