小木棍
1.分析:
此题可以理解为 “若干物品正好放入若干盒子的问题”;
对bfs的理解增加了:
初始状态为每个盒子都是空的,结尾状态为每个盒子都放好了,转移方法为“找一个物品放进去”,然后搜索就开始了
2.大概思想题解都有了,讲讲自己的强调和补充:
a.这种小数据二分确实用处不大
b.很重要的一个剪枝:当前长棍剩余的未拼长度等于原始长度时,说明这根原来的长棍还一点没拼,现在正在放入一根木棍。很明显,这根木棍还没有跟其它棍子拼接,如果现在拼下去能成功话,它肯定是能用上的,即自组或与其它还没用的木棍拼接。但继续拼下去却失败,说明现在这根木棍不能用上,无法完成拼接,这跟木棍现在不用放到后面用也用不上,所以回溯改之前的木棍。
c.拼第k个木棍时,dfs中对于i类型木棒,能用就用完,这是错的(如代码)
for(int i = l; i <= kind; i++) { if(num[i] && len[i]<= res) { int tmp = min(num[i], res / len[i]); if(len[i] == res*tmp)//进入拼下一根木棍 { num[i]-tmp; dfs(k+1, lenMg, 1); num[i]+=tmp; break;//如果恰好这么长行了,自动退出没毛病;如果恰好这么长都不行,比它短的来更不行了 if(res == lenMg) return;//及其重要的一个剪枝(因为是第一根木棍,长的肯定要放在这里了) } else { num[i]-=tmp; dfs(k, res-len[i]*tmp, i); num[i]+=tmp; if(res == lenMg) return;//及其重要的一个剪枝 } } }
原因:这是由链接题解中“几根组成x 比 1根x更灵活”的结论推出,但是这里5+5不一定能被2+2+2+2+2完全代替,因为有的时候大数字并不能被小数字拼出,比如5+4+1/4+3+3,这时候就不可能把两个4放在一起了
结尾放代码
#include<iostream> #include<algorithm> using namespace std; int kind, len[100], num[100];//kind木棍, 第i种长len[i],第i种有Nump[i]根可用 int maxLen = 0, sum = 0; int numMg, lenMg;//需要的木棍数,需要的木棍的长度 bool flag = 0;//标记找到答案没 void input() { int n, a[100]= {0}; cin >> n; while(n--) { int tmp; cin >> tmp; if(tmp <= 50) { a[++kind] = tmp; sum += tmp; maxLen = max(maxLen, tmp); } } n = kind; kind = 0; sort(a+1, a+1+n); for(int i = n; i >= 1; i--) { if(a[i] != len[kind]) { kind++; len[kind] = a[i]; num[kind] = 1; } else num[kind]++; } /*/cout test { cout <<kind<<":"<<endl; for(int i = 1; i <= kind; i++) { cout << len[i]<<" "<<num[i]<<endl; } } */ } void dfs(int k, int res, int last)//正在拼第k根,第k根还有res的长度需要拼,上一次使用的木棍类型 { if(flag) return; if(k == numMg+1) { flag = 1; return; } /* int l=last, r=kind, mid; while(l<r){ mid=(l+r)>>1; if(len[mid] <= res) r=mid; else l=mid+1; } */ for(int i = last; i <= kind; i++) { if(num[i] && len[i]<= res) { if(len[i] == res)//进入拼下一根木棍 { num[i]--; dfs(k+1, lenMg, 1); num[i]++; break;//如果恰好这么长行了,自动退出没毛病;如果恰好这么长都不行,比它短的来更不行了 if(res == lenMg) return; } else { num[i]--; dfs(k, res-len[i], i); num[i]++; if(res == lenMg) return; } } } } int main() { input(); for(int i = maxLen; i <= sum/2; i++) { if(sum%i==0) { numMg = sum/i; lenMg = i; flag = 0; dfs(1, lenMg, 1); if(flag) { cout << i; return 0; } } } cout <<sum<<endl; return 0; }

浙公网安备 33010602011771号