POJ 1014 解題報告

2021-06-27 01:19:39 字數 2809 閱讀 1923

這道題我用的是最原始的dfs,雖然加了cache,避免了一些重複運算,但不出意料地tle了。然後就是「優化」。把每個value中的item個數減到200以下(看discuss可以取到30甚至6的,還有一堆mod的解法)。我都不明白這些優化的原理。見源**中注釋掉的dfs部分。

1014

accepted

3736k

422ms

g++2013b

看到discuss中提到這道題可以用揹包做。然後看了傳說中的揹包九講,大致了解了,最終ac了。鏈結見

1014

accepted

916k

16ms

g++3727b

這道題用揹包的角度看就是個多重揹包問題,即有6個物品,每個物品能拿的件數是有上限的,這道題裡面就是輸入的數目,這道題裡面第i個物品的價值是i + 1(因為我是從0~5編號的)。

然後就可以寫出樸素的多重揹包解法:

int goal = sum / 2;

fill(dp.begin(), dp.begin() + goal + 1, int_min);

dp[0] = 0;

for (int i = 0; i < 6; ++i)

}}if (dp[goal] == goal)

else

這道題實質是看價值goal能不能通過在6個物品中各拿一定件數獲得,所以最終判斷dp[goal]==goal.中間的狀態轉移也是對每件物品的每個件數,看拿之前的那個價值能不能到達這個價值。初始化可以都初始成0,這樣表示所有價值中只有0到了(沒有拿任何item)。也可以把別的都初始化成int_min。應該不影響。

這樣做最後會tle,因為每個物品的件數可能很多,迴圈的常數太大。乙個優化是揹包九講中提到的。把物品能取的上限w分成多個「物品」,每個物品的係數分別是1, 2, 4, ..., 2^(k - 1), w - 2^k - 1。其中k是使得w - 2^k - 1>0的最大k。比如13只用試1, 2, 4, 6。雖然轉化成了0~1揹包,但是原來同乙個物品產生出來的這些「物品」都是在前乙個「物品」的基礎上更新dp的,所以他們之間實質是疊加關係。而這樣取係數的方式保證了所有1~w之間的所有數都是能取到的。具體分析見揹包九講。這個優化力度是非常大的。直接就從tle到了16ms。

for (int i = 0; i < 6; ++i)

// }

int w = nums[i];

for (int k = 1; k < w; k <<= 1)

w -= k;

}for (int v = goal; v >= (i + 1) * w; --v)

}

/* 

id: thestor1 

lang: c++ 

task: poj1014 

*/#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std;

// std::vector> cache(60000, std::vector(6, false));

// bool dfs(int index, int total, const int goal, int nums)

// // assert (total < goal);

// if (index < 0)

// // if (cache[total][index])

// // cache[total][index] = true;

// for (int i = 0; i <= nums[index]; ++i)

// // }

// }

// return false;

// }

// int main1()

// // int sum = 0;

// for (int i = 0; i < 6; ++i)

// // sum += nums[i] * (i + 1);

// }

// if (sum == 0)

// // if (sum & 1)

// // else

// // }

// int index = 5;

// while (nums[index] == 0)

// // assert(index >= 0);

// int total = index + 1;

// nums[index]--;

// if (dfs(index, total, goal, nums))

// // else

// // }

// seq++;

// }

// return 0;  

// }

std::vectordp(60001, 0);

int main()

if (sum == 0)

if (sum & 1)

else

// }

int w = nums[i];

for (int k = 1; k < w; k <<= 1)

w -= k;

}for (int v = goal; v >= (i + 1) * w; --v)

}if (dp[goal] == goal)

else

}seq++;

}return 0;

}

poj解題報告 1014

題意 有分別價值為1,2,3,4,5,6的6種物品,輸入6個數字,表示相應價值的物品的數量,問一下能不能將物品分成兩份,是兩份的總價值相等,其中乙個物品不能切開,只能分給其中的某一方,當輸入六個0是 即沒有物品 這程式結束,總物品的總個數不超過20000 如下 include includeint ...

poj 1014 硬幣分割

poj 1014 經典多重揹包問題 by baiwenlei 題目大意 給出一些價值在1 6範圍間的彈珠,判斷是否能夠按照價值等分 解題思路 多重揹包問題,不過本題中若價值不是偶數,直接返回即可 最後注意輸出的時候要求case之間有乙個空行,最後乙個case結束以後不空行。否則presentatio...

POJ1014幾種解法小結

第一種解法 dp 感覺不像 思想 本題是找按價值均分大理石的方案是否存在,由於分配時不能破壞大理石,所以有個顯而易見的剪枝 當所有的大理石的總價值為奇數時肯定不能被均分。把 問題轉化一下即 由乙個人能否從原大理石堆中取出總價值為原來一半的大理石,本題的主要演算法是動態規劃,陣列flag代表狀態,設總...