dfs剪枝与优化

搜索树

剪枝方法

1.优化搜索顺序

2.排除等效冗余

3.可行性

4.最优性(估价)

5.记忆化(树形不会重复计算时不需要)

 

A.针对每个维度边界信息缩放、推倒

B.计算未来最少花费

C.结合各维度的联系

 

P1120 小木棍 

https://www.luogu.org/problemnew/show/P1120

bool dfs(int p,int u,int x)
{
  if(p>cnt) return 1;
  if(u==len) return dfs(p+1,0,1);
  int lf=0;
  FOR(i,x,n)
    if((!vis[i])&&a[i]+u<=len&&a[i]!=lf)//剪枝2
      {
    vis[i]=1;
    if(dfs(p,a[i]+u,i+1)) return 1;
    vis[i]=0;lf=a[i];
    if(u+a[i]==len||u==0) return 0;//剪枝3.4
      }
  return 0;
}
int main()
{
  //freopen("hh.in","r",stdin);
  nnn=rd();
  FOR(i,1,nnn)
  {
    int tptp=rd();
    if(tptp>50) continue;
    a[++n]=tptp,cc+=a[n],gmax(mx,a[n]);
  }
  sort(a+1,a+n+1,greater<int>() );
  //FOR(i,1,n) cout<<a[i]<<" ";cout<<endl;
  for(len=mx;len<=cc;++len)
    {
      if(cc%len) continue;
      cnt=cc/len;
      memset(vis,0,sizeof(vis));
      if(dfs(1,0,1)){cout<<len;break;}
    }
  return 0;
}

 

P1731 [NOI1999]生日蛋糕

https://www.luogu.org/problemnew/show/P1731

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
#define FOR(i,a,b) for(register int i(a);i<=b;++i)
#define For(i,a,b) for(register int i(a);i>=b;--i)
int mins[20],minv[20];
int ans=1<<30,s;
bool prune(int maxh,int maxr,int n,int v)
{
    int cc=0;
    FOR(i,0,n-1) cc+=(maxh-i)*(maxr-i)*(maxr-i);
    if(cc<v) return 1;
    else return 0;
}
void dfs(int maxh,int maxr,int n,int v,int m)
{
    if(n==0)
    {
        if(v) return;
        ans=min(ans,s);
    }
    if(s+mins[n]>ans) return;
    if(maxh<n||maxr<n) return;
    if(minv[n]>v)  return;
    if(prune(maxh,maxr,n,v)) return;
    For(i,maxr,n)
    {
        if(n==m) s=i*i;
        For(j,maxh,n)
        {
            s+=2*i*j;
            dfs(j-1,i-1,n-1,v-i*i*j,m);
            s-=2*i*j;
        }
    }
}
int main()
{
    int n,m;scanf("%d%d",&n,&m);
    FOR(i,1,m)
        mins[i]=mins[i-1]+2*i*i,
        minv[i]=minv[i-1]+i*i*i;
    if(n<minv[m]) printf("0");
    else
    {
        int maxh=(n-minv[m-1])/(m*m)+1;
        int maxr=sqrt((n-minv[m-1])/m)+1;
        dfs(maxh,maxr,m,n,m);
        if(ans==1<<30) printf("0");
        else printf("%d",ans);
    }

    return 0;
}

 

迭代加深

a.搜索树规模增长快

b.从小到大限制深度

 

 双向搜索

“终态”明确,路径可逆

 

CH2401 送礼物

http://contest-hunter.org:83/contest/0x20%E3%80%8C%E6%90%9C%E7%B4%A2%E3%80%8D%E4%BE%8B%E9%A2%98/2401%20%E9%80%81%E7%A4%BC%E7%89%A9

先从前(N/2+2)中选若干个,存放,排序,去重

再枚举后一半,二分查找对应的前一半的值

 1 void dfs1(int i, unsigned int sum) {
 2     if (i == half) {
 3         a[++m] = sum;
 4         return;
 5     }
 6     dfs1(i + 1, sum);
 7     if (sum + g[i] <= w) dfs1(i + 1, sum + g[i]);
 8 }
 9 
10 void calc(unsigned int val) {
11     int rest = w - val;
12     int l = 1, r = m;
13     while (l < r) {
14         int mid = (l + r + 1) / 2;
15         if (a[mid] <= rest) l = mid; else r = mid - 1;
16     }
17     ans = max(ans, a[l] + val);
18 }
19 
20 void dfs2(int i, unsigned int sum) {
21     if (i == n + 1) {
22         calc(sum);
23         return;
24     }
25     dfs2(i + 1, sum);
26     if (sum + g[i] <= w) dfs2(i + 1, sum + g[i]);
27 }
28 
29 int main() {
30     cin >> w >> n;
31     for (int i = 1; i <= n; i++) scanf("%d", &g[i]);
32     sort(g + 1, g + n + 1);
33     reverse(g + 1, g + n + 1);
34     half = n / 2 + 3;
35     dfs1(1, 0);
36     sort(a + 1, a + m + 1);
37     m = unique(a + 1, a + m + 1) - (a + 1);
38     dfs2(half, 0);
39     cout << ans << endl;
40 }

 

IDA*

估价函数+迭代加深

若当前深度+未来估价>深度限制,立即回溯

 

转载于:https://www.cnblogs.com/universeplayer/p/10508598.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值