DFS之剪枝与优化
剪枝方法:
-
优化搜索顺序
-
排除等效冗余
-
可行性剪枝
-
最优性剪枝
优质讲解:
小猫爬山
AC代码【两种剪枝】:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 20;
int n, m;
int w[N];
int ans = 30;
int sum[N];
void dfs(int now, int k)
{
if(k >= ans) return ; // 最优性剪枝【优化前TLE】
if(now == n){
ans = k;
return ;
}
for(int i=0; i<k; i++)
if(sum[i] + w[now] <= m){ // 可行性剪枝
sum[i] += w[now];
dfs(now + 1, k);
sum[i] -= w[now];
}
sum[k] = w[now];
dfs(now + 1, k + 1);
sum[k] = 0;
}
int main()
{
cin >> n >> m;
for(int i=0; i<n; i++) cin >> w[i];
sort(w, w + n, greater<int>()); // 优化搜索顺序【优化前88ms,优化后30ms】
dfs(0, 0);
cout << ans;
system("pause");
return 0;
}
木棒
剪枝:
-
优化搜索顺序
-
可行性剪枝
-
排除等效冗余
1.按照组合数方式枚举,避免重复
2.长度等效跳过
3.4.详细思路见第一个链接
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 100;
int n;
int w[N];
int len, cases;
int vis[N];
// 按照组合数方式枚举,避免重复
// 思路:如果不是新开的组的话,要从上一个短木棍的后面start开始枚举,而不是从0开始,这样可以防止重复
bool dfs(int start, int cas, int sum)
{
if(cas == cases) return 1;
if(sum == len) return dfs(0, cas + 1, 0);
for(int i=start; i<n; i++)
{
if(vis[i]) continue;
if(sum + w[i] > len) continue; // 可行性剪枝
vis[i] = 1;
if(dfs(i + 1, cas, sum + w[i])) return 1;
vis[i] = 0;
if(sum == 0 || sum + w[i] == len) return 0;
if(i + 1 < n && w[i] == w[i + 1]) i ++ ; // 长度等效跳过
}
return 0;
}
int main()
{
while(scanf("%d", &n))
{
if(n == 0) break;
int sum = 0, minn = 200;
for(int i=0; i<n; i++) scanf("%d", &w[i]), sum += w[i], minn = min(minn, w[i]), vis[i] = 0;
sort(w, w + n, greater<int>());
len = minn;
while(1)
{
cases = sum / len;
if(sum % len == 0 && dfs(0, 0, 0)){
printf("%d\n", len);
break;
}
len ++ ;
}
}
system("pause");
return 0;
}
代码:没有写。