POJ 2362 解题报告
2015-09-18 06:07
323 查看
之前程序有个bug(更新下次从下一个棒子找),一直没有发现,总是TLE,最后改着改着就和discuss里面这个post一样了:
http://poj.org/showmessage?message_id=177718
这道题是DFS+剪枝。能否通过,重点还是在于保证正确性前提下的剪枝。
将棒子按照长度从大到小排序。这样做的原因是:1.排序肯定不会成为瓶颈(O(nlogn) vs O(n!))。排序还可以排除出有一根特长的棒子的情况(超过了边长)。2.从大到小找可以fail faster.
1.如果找得只剩下一组了,我们就不用再找了。剩下的一组肯定能拼出来。
2.如果是找一组的第一个棒子失败了,那么就不必接着找了。因为当前尝试的这个棒子是肯定可以作为新的组的第一个棒子的,失败的原因只能是之前的棒子已经组合错了,需要回溯,而不是接着尝试下一个棒子。
3.如果在同一组中,当前尝试的棒子和之前的棒子长度相同,那么这个棒子也可以直接跳过了。因为和之前那个棒子没有区别,肯定也会失败。
http://poj.org/showmessage?message_id=177718
这道题是DFS+剪枝。能否通过,重点还是在于保证正确性前提下的剪枝。
将棒子按照长度从大到小排序。这样做的原因是:1.排序肯定不会成为瓶颈(O(nlogn) vs O(n!))。排序还可以排除出有一根特长的棒子的情况(超过了边长)。2.从大到小找可以fail faster.
1.如果找得只剩下一组了,我们就不用再找了。剩下的一组肯定能拼出来。
2.如果是找一组的第一个棒子失败了,那么就不必接着找了。因为当前尝试的这个棒子是肯定可以作为新的组的第一个棒子的,失败的原因只能是之前的棒子已经组合错了,需要回溯,而不是接着尝试下一个棒子。
3.如果在同一组中,当前尝试的棒子和之前的棒子长度相同,那么这个棒子也可以直接跳过了。因为和之前那个棒子没有区别,肯定也会失败。
thestoryofsnow | 2362 | Accepted | 132K | 16MS | C++ |
/* ID: thestor1 LANG: C++ TASK: poj2362 */ #include <iostream> #include <fstream> #include <cmath> #include <cstdio> #include <cstring> #include <limits> #include <string> #include <vector> #include <list> #include <set> #include <map> #include <queue> #include <stack> #include <algorithm> #include <cassert> using namespace std; const int MAXM = 40; int sticks[MAXM]; bool visited[MAXM]; int M, LEN; const int MATCH = 4; bool dfs(int len, int matched, int index) { int now = -1; for (int i = index; i < M; ++i) { // if we have tried a stick with the same length and failed (we know from the fact that we are trying other sticks) // we don't need to try the same length again if (sticks[i] == now) { continue; } if (!visited[i] && sticks[i] <= len) { now = sticks[i]; visited[i] = true; if (sticks[i] == len) { if (matched == MATCH - 2) { // since we already matched 2 times, plus this time, // we are confident that whatever left is sufficient for the remaining last match return true; } else if (dfs(LEN, matched + 1, 0)) { return true; } else { // since can not find a new match from scratch, // we don't need to try next stick visited[i] = false; return false; } } else { if (dfs(len - sticks[i], matched, i + 1)) { return true; } visited[i] = false; if (len == LEN) { // since can not find a new match from scratch (and this stick should be part of a match), // we don't need to try next stick return false; } } } } return false; } int main() { int N; scanf("%d", &N); for (int t = 0; t < N; ++t) { scanf("%d", &M); int sum = 0; for (int i = 0; i < M; ++i) { scanf("%d", &sticks[i]); sum += sticks[i]; } if (sum % 4 != 0 || M < 4) { printf("no\n"); } else { LEN = sum / 4; sort(sticks, sticks + M, greater<int>()); // printf("sticks:\n"); // for (int i = 0; i < M; ++i) // { // printf(" %d\n", sticks[i]); // } // printf("\n"); if (sticks[0] > LEN) { printf("no\n"); continue; } for (int i = 0; i < M; ++i) { visited[i] = false; } if (dfs(LEN, 0, 0)) { printf("yes\n"); } else { printf("no\n"); } } } return 0; }
相关文章推荐
- 偶有一个计划,希望坚持!
- 9.17学习总结
- jQuery简单实现两级下拉菜单效果代码
- JavaScript 封装一个tab效果源码分享
- count(*)和count(列)之争
- 基于jQuery倾斜打开侧边栏菜单特效代码
- JS+CSS实现带有碰撞缓冲效果的竖向导航条代码
- jquery点击缩略图切换视频播放特效代码分享
- jQuery焦点图切换特效代码分享
- JS实现带有抽屉效果的产品类网站多级导航菜单代码
- jquery图片轮播特效代码分享
- jquery带有索引按钮且自动轮播切换特效代码分享
- jQuery实现可展开合拢的手风琴面板菜单
- JQuery实现图片轮播效果
- jQuery带进度条全屏图片轮播特效代码分享
- 9.16学习总结
- 自定义(外观)Switch开关
- Log4j与common-logging联系与区别
- H-Index
- LeetCode-Missing Number