杭电1455 dfs 剪枝

杭电1455点这里

#include<cstdio>  
#include<cstring>  
#include<cmath>  
#include<cstdlib>  
#include<iostream>  
#include<algorithm>  
#include<vector>  
#include<map>  
#include<queue>  
#include<stack> 
#include<string>
#include<map> 
#include<set>
#define eps 1e-6 
#define LL long long  
using namespace std;  
 
const int maxn = 70;
const int INF = 0x3f3f3f3f;
int n, sumv, target, aim;//target表示目标的棍子个数,aim表示目标的棍子长度 
int stick[maxn], vis[maxn];
bool cmp(int a, int b) {
    
    
	return a > b;
}
 
void init() {
    
    
	sumv = 0;
	for(int i = 0; i < n; i++) {
    
    
		cin >> stick[i]; sumv += stick[i];
	}
	sort(stick, stick+n, cmp);
}
 
bool dfs(int cnt, int len, int pos) {
    
    
	if(cnt == target) return true;
	if(len == aim) return dfs(cnt+1, 0, 0); 
	for(int i = pos; i < n; i++) {
    
                             //从大到小排序后,按顺序搜索 
		if(!vis[i] && len+stick[i] <= aim) {
    
    
			vis[i] = 1;
			if(dfs(cnt, len+stick[i], i+1)) return true;
			vis[i] = 0;                                     
			if(len == 0) return false;                     //如果第一根时失败剪枝 
			while(i+1 < n && stick[i+1] == stick[i]) i++;  //如果下一根长度跟当前的失败的长度一样,剪枝 
		}
	}
	return false;
}
 
void solve() {
    
    
	int ans = 0;
	for(int i = 1; i <= sumv; i++) if(sumv % i == 0) {
    
    
		memset(vis, 0, sizeof(vis));
		aim = i; target = sumv / aim;
		if(dfs(0, 0, 0)) {
    
    
			ans = aim; break;
		}
	}
	cout << ans << endl;
}
 
int main() {
    
    
//	freopen("input.txt", "r", stdin);
	while(scanf("%d", &n) == 1 && n) {
    
    
		init();
		solve();
	}
	return 0;
}
 

以上这个大佬的代码
附上一点我的代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
int n,num,l[70],f[70],r,ans,c;
bool cmp(int a,int b)
{
    
    
    return a>b;
}
bool dfs(int d,int len,int pos)
{
    
    
    if(d==c)   return true;
    if(len==r) return dfs(d+1,0,0);
    for(int i=pos; i<n; i++)
    {
    
    
        if(!f[i]&&len+l[i]<=r)
        {
    
    
            f[i]=1;
            if(dfs(d,len+l[i],i+1))return true;
            f[i]=0;
            if(len == 0) return false;
            while(i+1 < n && l[i+1] == l[i]) i++;
        }
    }
    return false;

}
int main()
{
    
    
    while(scanf("%d",&n)!=EOF,n)
    {
    
    
        num=0;
        for(int i=0; i<n; i++)
        {
    
    
            scanf("%d",&l[i]);
            num+=l[i];
        }
        sort(l,l+n,cmp);
        for(int i=1; i<=num; i++)
        {
    
    
            memset(f,0,sizeof f);
            if(num%i==0)
            {
    
    
                c=num/i;
                r=i;
                if(dfs(0,0,0))
                {
    
    
                    ans=r;
                    break;
                }

            }
        }
        cout<<ans<<endl;
    }
}

这题和之前我们刚开始学深搜练习第一题有点像点这里(杭电1518)
有一个巧妙的小剪枝相同:就是在写dfs时排序从大到小,然后在已经用过的线段后直接从下一个线段开始可以避免之前的,因为前面的是大于等于边长的一定不可能,所以很妙,1455的这题要求更高,时间卡的更紧一点,本人也是刚开始学习dfs和剪枝,所以学习了那位前辈的代码,但是我联想到了那道(hd1518),所以我还是懂一点剪枝的(不要笑我这个萌新),但是1455的剪枝优化更好,在于如果第一根时失败,剪枝如果下一根长度跟当前的失败的长度一样,剪枝

if(len == 0) return false;                     //如果第一根时失败剪枝 
while(i+1 < n && stick[i+1] == stick[i]) i++;  //如果下一根长度跟当前的失败的长度一样,剪枝 

但是我还是没有理解第一行的代码,为什么第一根失败了就剪枝,
第二行的代码总体和那个for里面的意思差不多。

Guess you like

Origin blog.csdn.net/weixin_51626694/article/details/116094434
dfs