**dfs剪枝**
主要难点在于如何进行dfs的剪枝,典型例题如小木棍
[洛谷p1120小木棍](https://www.luogu.org/problem/show?pid=1120)
可以二分答案(不二分也不会超时,我的代码没有二分),dfs看看这个答案可不可行
虽然数据很小,直接dfs也是会超时的,所以需要加入一些剪枝。
1.从max(最大木棍长度,总木棍长度/要分的段数)为左面,所有木棍长度为右面二分答案。
2.木棍长度要排序,方便每次dfs从小到大,为避免重复搜索(比如说2 3 4 和2 4 3)定义一个pos,每次枚举从pos开始,这也是为什么排序的原因之一。
3.如果现在搜索状态的剩余长度和二分答案的长度相等,还搜不出答案,说明有木棍无解,直接break跳出循环。
4.如果现在搜索状态的剩余长度和循环搜索到木棍的长度相等,那么下一次dfs的状态如3,还搜不出答案,说明有木棍无解,直接break跳出循环。
5.如果这个长度的木棍搜不出答案,相同长度的也搜不出答案。
下面是满分代码(ac数据加强版)
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
bool vis[101];
int n,a[101],tot,all,len;
int cmp(int x,int y)
{
return x>y;
}
bool dfs(int now,int pos,int d)
{
if(d==tot)
{
return 1;
}
if(now==0)
if(dfs(len,1,d+1)==1) return 1;
for(int i=pos;i<=n;++i)
if(vis[i]==0&&a[i]<=now)
{
vis[i]=1;
if(dfs(now-a[i],i+1,d)) return 1;
vis[i]=0;
if(now==a[i]||now==len) break; //3,4
while(a[i+1]==a[i]) i++; //5
}
return 0;
}
int main()
{
cin>>n;
for(int i=1;i<=n;++i)
{
cin>>a[i];
if(a[i]>50)
{
i--;n--;
}
else all+=a[i];
}
sort(a+1,a+1+n,cmp); //2
for(int i=a[1];i<=all;++i) //1
{
if(all%i==0)
{ len=i;
tot=all/i;
if(dfs(len,1,0)==1)
{
cout<<len;
return 0;
}
}
}
}
版权声明:本文为Tekim原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。