洛谷:P1120 小木棍 [数据加强版](剪枝搜素)

题目:

在这里插入图片描述

分析:二分和树都比较简单,本来想着再水一波简单的,但是搜搜题好像都有一定的难度。

直接看的答案。

首先思考不能二分。因为答案不满足特点。(可以意会)

1.题目缺陷:

在这里插入图片描述

2.要求的是原始木棍的最小可能长度,那么我枚举开始答案是木棍现长的最大值。然后不断加最小的。

3.在判断一个答案是否符合要求的时候,应该:优先使用长的木棍。

4.在判断一个答案是否符合要求的时候,首先应该整除总长度。

嗯,可以写代码了。

代码:我咋感觉不用搜索呢!用的 ,。

#include<bits/stdc++.h>
using namespace std;
vector<vector<int> > vv;
int m;
vector<int> v;
int maxx=-1;
int done[100];
int sum_len=0;
void f(int k,int rest,int goal,int sum_len)
{
//k  当前在拼第几根
//rest 表示当前在拼的长棍还有多少长度未拼
//goal 表示当前进行测试的长度 
//sum_len 表示木棍组合起来的总长度 
 if(k*goal==sum_len) {
  cout<<goal;
  exit(0);
 }
 if(rest==0) f(k+1,goal,goal,sum_len);//满足条件,下一轮
 int last=-1;
 for(int i=v.size()-1;i>=0;i--)
 {
  if(done[i]==1) continue;
  if(last==-1) last=i;
  else if(v[last]==v[i]) continue;
  if(v[i]<=rest) 
  {
   done[i]=1;
   f(k,rest-v[i],goal,sum_len);
   done[i]=0;
  }
 }
}
int main()
{
 cin>>m;
 for(int i=0;i<m;i++)
 {
  int c; cin>>c;
  if(c<=50) 
  {
   v.push_back(c);
   maxx=max(maxx,c);
   sum_len+=c;
  }
 }
 for(int i=maxx;;i++)
 {
  if(sum_len%i!=0) continue;
  memset(done,0,sizeof(done)); 
  f(1,i,i,sum_len);
 } 
}

结果:

在这里插入图片描述

修改粗心导致的忘记排序,以及忘记修改last:

在这里插入图片描述

去掉多余的memset:

在这里插入图片描述

我感觉你说的优化我都用了,还t?先放弃了:

#include<bits/stdc++.h>
using namespace std;
vector<vector<int> > vv;
int m;
vector<int> v;
int maxx=-1;
int done[100];
int sum_len=0;
void f(int k,int rest,int goal,int sum_len)
{
//k  当前在拼第几根
//rest 表示当前在拼的长棍还有多少长度未拼
//goal 表示当前进行测试的长度 
//sum_len 表示木棍组合起来的总长度 
 if(k*goal==sum_len) {
  cout<<goal;
  exit(0);
 }
 if(rest==0) f(k+1,goal,goal,sum_len);//满足条件,下一轮
 int last=-1;
 for(int i=v.size()-1;i>=0;i--)
 {
  if(done[i]==1) continue;
  if(last==-1) last=i;
  else if(v[last]==v[i]) continue;
  last=i;
  if(v[i]<=rest) 
  {
   done[i]=1;
   f(k,rest-v[i],goal,sum_len);
   done[i]=0;
  }
 }
}
int main()
{
 cin>>m;
 for(int i=0;i<m;i++)
 {
  int c; cin>>c;
  if(c<=50) 
  {
   v.push_back(c);
   maxx=max(maxx,c);
   sum_len+=c;
  }
 }
 sort(v.begin(),v.end());
 for(int i=maxx;;i++)
 {
  if(sum_len%i!=0) continue;
  memset(done,0,sizeof(done)); 
  f(1,i,i,sum_len);
 } 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值