深度优先搜索

#include<iostream>
using namespace std;
int a[10], book[10], n;
void dfs(int step) {
    int i;
    if (step == n + 1) {
        for (i = 1; i <= n; i++)
            cout << a[i];
        cout << endl;
        return;
    }
    for (i = 1; i <= n; i++) {//把每一种情都去尝试一下
        if (book[i] == 0) {
            a[step] = i;
            book[i] = 1;
            dfs(step + 1);//再去下一个箱子
            book[i] = 0;
        }
    }
}
int main() {
    cin >> n;
    dfs(1);
    getchar();
    getchar();
    return 0;
}

void dfs(int step) {
    //判断边界
    //尝试每一种可能for(i=1;i<=n;i++){
    //继续下一步 dfs(step+1);
}
//返回
}

#include<iostream>
using namespace std;
int a[10], book[10], total = 0;
void dfs(int step) {
    int i;
    if (step == 10) {
        if (a[1] * 100 + a[2] * 10 + a[3] + a[4] * 100 + a[5] * 10 + a[6] == a[7] * 100 + a[8] * 10 + a[9]) {
            total++;
            cout << a[1] << a[2] << a[3] << a[4] << a[5] << a[6] << a[7] << a[8] << a[9];
        }
        return;//返回之前的一步 
    }
    //站在第step个盒子之前 应该放那张牌呢?
    for (i = 1; i <= 9; i++) {
        if (book[i] == 0) {
            a[step] = i;
            book[i] = 1;
            dfs(step + 1);
            book[i] = 0;
        }
    }
    return;
}
int main() {
    dfs(1);
    cout << total / 2;
    getchar();
    getchar();
    return 0;
}

  1. 改变搜索顺序。这一道题的输入数据是一个不下降序列,如果我们把小的数放在前面,而 �C 又比较大的话,前面的小数就会有很多的空间进行选择,极限数据下甚至可以卡死代码。为了避免这种情况,我在读入的时候从 ��an​ 开始倒着读,这样 a 数组中就是一个不上升子序列,前面的大数很容易就因为 �C 的限制失去很多选择,节省了很多的时间。其中 a 数组是我存放数的数组。
  2. 模拟可行性剪枝,我们不妨这么想:如果说当前所选的数的总和加上后面的数的总和,即后缀和都没有超过 �C 的话,那么当前的和就是在这种选择下可以达到的最大值。既然我们已经知道了最大值,并且题目所求的就是最大值,此时我们可以直接去更新答案, 然后退出这一层搜索。面对数很多的时候,这个剪枝会发挥出极大的威力。

在这些优化下,搜索的复杂度会变得很低。当然,如果您有什么更好的优化方法或剪枝,请私信我,感谢!

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1000+10;
int n,c,a[MAXN];//n c 如题 a 存放数 
typedef long long LL;
LL sum[MAXN],ans;//sum 后缀和 ans 答案 
LL Max(LL fir,LL sec)
{
	return (fir>sec)?fir:sec;
}
void dfs(int k,int now)
{
	if(k>n)//选完了 
	{
		ans=Max((LL)now,ans); 
		return;
	}
	if(now+sum[k]<=c)//优化2 
	{
		ans=Max(now+sum[k],ans);
		return;
	}
	if(now+a[k]<=c) dfs(k+1,now+a[k]);
	dfs(k+1,now);
}
int main()
{
	scanf("%d %d",&n,&c);
	for(int i=n;i>=1;i--) scanf("%d",&a[i]);//优化1 
	for(int i=n;i>=1;i--) sum[i]=sum[i+1]+a[i];
	dfs(1,0);
	printf("%lld\n",ans);
	return 0;
}

 9   3 条评论收起 

SweatBoy创建时间:2019-10-04 15:21:44

在 Ta 的博客查看

斐波那契数列,很快就会超过2^30,N<40

所以题目的(1<=n<=1000)是来吓人的

所有题目变得简单一点了

---------------------------好,进入正题-----------------------------

上代码

#include <bits/stdc++.h>//万能头文件 
using namespace std;
const int N = 5101000;
int ans[N],n,C,m,a[N];
void DFS(int step,int lim,int w){
	if(step>lim){
		ans[m++]=w;
		return;
	}
	DFS(step+1,lim,w);//递归 
	DFS(step+1,lim,w+a[step]);//递归
}
int main() {
	scanf("%d%d",&n,&C);//输入,同cin>>n>>C; 
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);.//输入,同cin>>a[i]; 
	}
	DFS(1,n/2,0);
	int left =m;
	DFS(1+n/2,n,0);
	sort(ans,ans+left);//排序,前left-1 
	sort(ans+left,ans+m);//排序,从left到m-1 
	int res=0;
	int j=m-1;
	for(int i=0;i<left;i++){
		while(ans[i]+ans[j]>C&&j>left){
			j--;
		}
		if(ans[i]+ans[j]<=C){
			res=max(res,ans[i]+ans[j]);//c++自带的max 
		}
	}
	printf("%d\n",res);//输出,同cout << res << endl; 
	return 0;
}

希望各位同志能看懂!!!

希望管理员给通过!!!

谢谢各位!!!

展开全文 

 8   3 条评论

hylong创建时间:2019-08-30 22:13:31

在 Ta 的博客查看

这是道搜索题,用DFS可以跑到25ms甚至更快 (当然,我没有跑到过)。

阅读题目:

天平能承受的物体的质量不是无限的,当天平某一边物体的质量大于 �(1≤�≤230)C(1≤C≤230)时,天平就会被损坏。砝码按照它们质量的大小被排成一行。并且,这一行中从第3个砝码开始,每个砝码的质量至少等于前面两个砝码(也就是质量比它小的砝码中质量最大的两个)的质量的和

想到了什么?(斐波那契数列)

#include<bits/stdc++.h>
using namespace std;
int main()//求斐波那契数列代码
{
	long long i,j,k,n=47,a=1,b=1,c;
	for(i=3;i<=n;i++)
	{
	 c=a+b;
	 a=b;
	 b=c;
	}
	cout<<b<<endl;
	cout<<(long long)pow(2,30)<<endl;
	cout<<(long long)pow(2,31)<<endl;
	return 0;
}
  • fib(47)=2971215073;
  • 230230=1073741824;
  • 231231=2147483648;
  • 所以n最多为47,搜索就可以解决。
得分历程:
  1. 打了个搜索还打错了,得了10分。
  2. 打了个对的暴搜,60分(及格了)
  3. 用前缀和优化了一下,100分(25ms)
代码:

60分代码(TLE3个点)

#include<bits/stdc++.h>
using namespace std;
long long a[101],n,c,ans;
void dfs(long long xh,long long w)
{
	ans=max(ans,w);
	if(xh==0)
	 return ;
	if(w+a[xh]<=c)
	 dfs(xh-1,w+a[xh]);
	dfs(xh-1,w);
}
inline long long read()
{
	long long x=0;
	char b=getchar();
	while(b>'9' || b<'0')
	 b=getchar();
	while(b>='0' && b<='9')
	{
	 x=x*10+b-'0';
	 b=getchar();
	}
	return x;
}
int main()
{
	long long i,maxn=0;
	n=read();c=read();
	for(i=1;i<=n;i++)
	{
	 a[i]=read();
	 if(a[i]<c)
	  maxn=i;
	}
	dfs(maxn,0);
	cout<<ans<<endl;
	return 0;
}

100分代码(没开O2,25ms)

#include<bits/stdc++.h>
using namespace std;
long long a[101],n,c,ans;
long long sum[101];//前缀和
void dfs(long long xh,long long w)
{
	ans=max(ans,w);
	if(xh==0)
	 return ;//边界
	if(sum[xh]+w<=c)
	{
	 ans=max(ans,sum[xh]+w);
	 return ;
	}//剪枝
	if(w+a[xh]<=c)//也算是一个剪枝吧
	 dfs(xh-1,w+a[xh]);
	dfs(xh-1,w);
}//深搜+剪枝
inline long long read()
{
	long long x=0;
	char b=getchar();
	while(b>'9' || b<'0')
	 b=getchar();
	while(b>='0' && b<='9')
	{
	 x=x*10+b-'0';
	 b=getchar();
	}
	return x;
}//玄学快读(加inline可能会更慢)
int main()
{
	long long i,maxn=0;
	n=read();c=read();
	for(i=1;i<=n;i++)
	{
	 a[i]=read();
	 sum[i]=sum[i-1]+a[i];//保存前缀和
	 if(a[i]<c)
	  maxn=i;
	}
	dfs(n,0);//其实相当于dfs(maxn,0),之前maxn忘记删了,现在有懒得删了
	cout<<ans<<endl;//输出
	return 0;
}

展开全文 

 6   0 条评论

kfhkx创建时间:2019-03-03 09:47:25

在 Ta 的博客查看

看到题解里没有Pascal,就来一波吧~

刚开始看到这一题的数据范围就被吓懵了

1<=C<=2^30这还能做吗

不过再仔细看题就发现题目中有一句这样的话

  • 并且,这一行中从第3个砝码开始,每个砝码的质量至少等于前面两个砝码(也就是质量比它小的砝码中质量最大的两个)的质量的和。

即a[3]>=a[2]+a[1]取等时

这不就是暗示我们是某Fibonacci数列吗!!!

在32位范围内不就只有不到50个数吗,发现这个之后这题就好办了~

即我们只要爆搜小于50次就能找到答案

补充一点小优化~

  • 计算前缀和可以边读入边累加
  • 特判一:如果读入的数恰好等于m就直接输出m并退出
  • 特判二:如果读入的数大于了m就把他删去,并要:
  1. 在前缀和里面去掉

  2. a[i]:=0;

  3. 因为读入是递增的所以直接退出循环并将n赋值为i+1

多的不用说了,下面就是爆搜(dfs)+小优化的代码

p5194.pas

var
        i:longint;
        n,m,ans:int64;//这里和下面几个地方一定要开int64,不然只有60分
        a,sum:array[0..10000] of int64;
function max(x,y:int64):int64;//自定义max函数
begin
        if x>y then exit(x) else exit(y);
end;
procedure dfs(x,y:int64);//爆搜开始
var
        i:longint;
begin
        if y>m then exit;//如果当前y>m那么就证明继续也找不到解,故直接exit掉
        if sum[x-1]+y<m then begin
                ans:=max(ans,sum[x-1]+y);
                exit;
        end;
        ans:=max(ans,y);
        for i:=1 to x-1 do dfs(i,a[i]+y);
        exit;
end;
begin
        read(n,m);
        for i:=1 to n do begin
                readln(a[i]);
                sum[i]:=sum[i-1]+a[i];//前缀和预处理
                if a[i]=m then begin//特判一
                        writeln(m);
                        exit;
                end else if a[i]>m then begin//特判二
                        a[i]:=0;
                        sum[i]:=sum[i]-a[i];//减去无用数据
                        break;
                end;
        end;
        n:=i+1;//特判二之后能减少一些没有用的数据
        dfs(n,0);
        writeln(ans);
end.

展开全文 

 5   0 条评论

Drinkkk创建时间:2019-02-23 07:34:33

在 Ta 的博客查看

DescriptionDescription

约翰有一架用来称牛的体重的天平。与之配套的是 �N ( 1≤�≤10001≤N≤1000 )个已知质量的砝码(所有砝码质量的数值都在 32 位带符号整数范围内)。

每次称牛时,他都把某头奶牛安置在天平的某一边,然后往天平另一边加砝码,直到天平平衡,于是此时砝码的总质量就是牛的质量(约翰不能把砝码放到奶牛的那边,因为奶牛不喜欢称体重,每当约翰把砝码放到她的蹄子底下,她就会尝试把砝码踢到约翰脸上)。

天平能承受的物体的质量不是无限的,当天平某一边物体的质量大于 �C ( 1≤�≤2301≤C≤230 ) 时,天平就会被损坏。砝码按照它们质量的大小被排成一行。并且,这一行中从第3个砝码开始,每个砝码的质量至少等于前面两个砝码(也就是质量比它小的砝码中质量最大的两个)的质量的和。

约翰想知道,用他所拥有的这些砝码以及这架天平,能称出的质量最大是多少。由于天平的最大承重能力为 �C ,他不能把所有砝码都放到天平上。

现在约翰告诉你每个砝码的质量,以及天平能承受的最大质量,你的任务是选出一些砝码,使它们的质量和在不压坏天平的前提下是所有组合中最大的。

SolutionSolution

观察一下题目的限制。

并且,这一行中从第3个砝码开始,每个砝码的质量至少等于前面两个砝码(也就是质量比它小的砝码中质量最大的两个)的质量的和。

���()?Fib()?

于是我们就可以得出

第  �  个砝码的重量>���(�)第i个砝码的重量>fib(i)

���(1)=���(2)=1fib(1)=fib(2)=1

���(�)=���(�−1)+���(�−2)      ∣      �>2fib(n)=fib(n−1)+fib(n−2)∣n>2

然后这道题的 �N 就可以成功缩小了。

然后就用最优化剪枝和前缀和维护一下就可以啦!

CodeCode

#include <cstdio>
#include <cstdlib>
#include <cmath>
long long su[1000001],a[1000001],t[1000001];
long long ans=0,n=0,c=0;
long long max(long long x,long long y)
{
	return x>y?x:y;
}
void dfs(long long x,long long y)
{
	if(y+su[x]<=ans)
	{
		return ;
	}
	if(y>c)
	{
		return ;
	}
	ans=max(ans,y);
	if(x==0)
	{
		return ;
	}
	dfs(x-1,y+a[x]);
	dfs(x-1,y);
}
int main()
{
	scanf("%lld %lld",&n,&c);
	su[0]=0;
	for(long long i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		su[i]=su[i-1]+a[i];
	}
	while(a[n]>c)
	{
		n--;
	}
	dfs(n,0);
	printf("%lld",ans);
	return 0;
}

展开全文 

 2   1 条评论

muller创建时间:2019-03-02 18:42:51

在 Ta 的博客查看

根据题目条件:

并且,这一行中从第3个砝码开始,每个砝码的质量至少等于前面两个砝码(也就是质量比它小的砝码中质量最大的两个)的质量的和。

然后max为1e9

我们可以证明有复杂度保证

有点玄学

所以我们可以直接爆搜

注意两个剪枝,可以适当提速

if (a[i] > C) {
    n = i - 1; break;
}
if (res + s[l] <= ans) return;

比较显然吧

code:

// luogu-judger-enable-o2
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define				MAXN				1010
LL a[MAXN], s[MAXN], C, ans = 0;
int n;
template <typename T> void read(T &x) {
	x = 0;int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-')f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
void work(register int l, LL res) {
	if (res + s[l] <= ans) return;
	ans = max(ans, res);
	for (register int i = l; i; i--)
		if (res + a[i] <= C) work(i - 1, res + a[i]); 
}
int main() {
	read(n); read(C);
	for (register int i = 1; i <= n; i++) {
		read(a[i]);
		if (a[i] > C) {
			n = i - 1; break;
		}
		s[i] = s[i - 1] + a[i];
	}
	work(n, 0);
	printf("%d\n", ans); 
	return 0;
}

展开全文 

 3   0 条评论

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值