這道題我用的是最原始的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代表狀態,設總...