Executing... Test 1: TEST OK [0.005 secs, 3392 KB] Test 2: TEST OK [0.005 secs, 3392 KB] Test 3: TEST OK [0.008 secs, 3392 KB] Test 4: TEST OK [0.097 secs, 3392 KB] Test 5: TEST OK [0.005 secs, 3392 KB] Test 6: TEST OK [0.062 secs, 3392 KB] Test 7: TEST OK [0.005 secs, 3392 KB] Test 8: TEST OK [0.011 secs, 3392 KB] Test 9: TEST OK [0.030 secs, 3392 KB] Test 10: TEST OK [0.005 secs, 3392 KB] Test 11: TEST OK [0.005 secs, 3392 KB] Test 12: TEST OK [0.008 secs, 3392 KB] All tests OK.
二分答案! 我真的没想到,看了nocow的题解。
把need从小到大排序
1、假设前k个need可以得到,那么首先可以知道前k个need木板的总和,也就可以计算出需要浪费的木板总量tot_wast。
因为已经精确到要浪费的总量了,某个切割方案让浪费的总量超过tot_wast,显然是无解的
2、因为只有128种数字,却有1000多木板,所以各种木板是重复的大小,这就有一个搜索次序的情况了。 比如有2个need木板都是5,5.
在当前的give的木板上,我切后一块,不要前一块。 这样会造成大量的重复运算,所以需要用一些方法来处理掉这些多余的计算量。
3、尝试要哪些need的时候,要从大到小!
for (int i = max_need; i >=0 ; -- i) { if (vis[i]) continue; if (len < need[i]) continue; //不够切的,也直接continue vis[i] = 1; //cut_num[i] = k; // i是被k切的 if (i && need[i] == need[i - 1] && !vis[i - 1]) { vis[i] = 0; continue; } flag = dfs(k, len - need[i], get + 1, wast); if (flag) return true; vis[i] = 0; IFUSD =true; }
for (int i = max_need; i >=0 ; -- i)
for (int i = 0; i <= <span style="font-family: Arial, Helvetica, sans-serif;">max_need</span> ; ++ i)
原因? 数据的原因嘛?我不认为如此。
首先众所周知,索树在开始的树枝被剪的效果永远比在结尾被剪效果来的好~
试大的,会很大程度的造成【快速浪费】,根据前面的浪费条件的剪枝原理,快速剪掉很多,快速出解。
/* TASK:fence8 LANG:C++ */ #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; int gived_num, need_num; int gived[55], need[1050]; int sum[1050]={0}; int tot_give(0); void init() { scanf("%d", &gived_num); for (int i = 0; i != gived_num; ++ i) scanf("%d", gived + i); for (int i = 0; i != gived_num; ++ i) tot_give += gived[i]; scanf("%d", &need_num); for (int i = 0; i != need_num; ++ i) scanf("%d", need + i); sort(need, need + need_num); sum[0] = need[0]; for (int i = 1; i != need_num; ++ i) sum[i] = need[i] + sum[i - 1]; //合计所用的材料 } int max_wast, max_need; bool vis[1050] = {false}; int cut_num[1050]; bool dfs(int k, int len, int get, int wast) //当前切第k个木料,第k个木料还剩多少长度, 浪费的总量 { if (wast > max_wast) return false; //过度浪费,不可能成功,失败 if (k == gived_num) return false; if (get == max_need) { //cout<<"成功"<<endl; return true; } bool flag = false; bool IFUSD = false; for (int i = max_need; i >=0 ; -- i) { if (vis[i]) continue; if (len < need[i]) continue; //不够切的,也直接continue vis[i] = 1; //cut_num[i] = k; // i是被k切的 if (i && need[i] == need[i - 1] && !vis[i - 1]) { vis[i] = 0; continue; } flag = dfs(k, len - need[i], get + 1, wast); if (flag) return true; vis[i] = 0; IFUSD =true; } //下一块木料,这个不用了 if (IFUSD) return false; //这块能切割,但是不切割,肯定是不行的,false flag = dfs(k + 1, gived[k + 1], get, wast + len); if (flag) return true; return false; } bool check(int k) //前k个need全部制作出来 { memset(vis, 0, sizeof(vis)); memset(cut_num, 0, sizeof(cut_num)); sum[k]; //合计使用的材料 max_wast = tot_give - sum[k]; //正好要浪费这么多材料,如果浪费更多,显然是不对的 //cout<<tot_give<<" "<<sum[20]<<endl; if (sum[k] > tot_give) return false; max_need = k; return dfs(0, gived[0], 0, 0); } void doit() { int max_gived=0; for (int i = 0; i != gived_num; ++ i) if (gived[i] > max_gived) max_gived = gived[i]; if (max_gived < need[0]) { printf("0\n"); return; } int left = 0, right = need_num; // [); int mid; while (left + 1 < right) //序号[left, right)合法 { mid = (left + right) / 2; if (check(mid)) left = mid; else right = mid; } cout << left + 1 << endl; } int main() { freopen("fence8.in","r",stdin); freopen("fence8.out","w",stdout); init(); doit(); return 0; }