#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;
}
- 改变搜索顺序。这一道题的输入数据是一个不下降序列,如果我们把小的数放在前面,而 �C 又比较大的话,前面的小数就会有很多的空间进行选择,极限数据下甚至可以卡死代码。为了避免这种情况,我在读入的时候从 ��an 开始倒着读,这样 a 数组中就是一个不上升子序列,前面的大数很容易就因为 �C 的限制失去很多选择,节省了很多的时间。其中 a 数组是我存放数的数组。
- 模拟可行性剪枝,我们不妨这么想:如果说当前所选的数的总和加上后面的数的总和,即后缀和都没有超过 �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
斐波那契数列,很快就会超过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
这是道搜索题,用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,搜索就可以解决。
得分历程:
- 打了个搜索还打错了,得了10分。
- 打了个对的暴搜,60分(及格了)
- 用前缀和优化了一下,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
看到题解里没有Pascal,就来一波吧~
刚开始看到这一题的数据范围就被吓懵了
1<=C<=2^30这还能做吗
不过再仔细看题就发现题目中有一句这样的话
- 并且,这一行中从第3个砝码开始,每个砝码的质量至少等于前面两个砝码(也就是质量比它小的砝码中质量最大的两个)的质量的和。
即a[3]>=a[2]+a[1]取等时
这不就是暗示我们是某Fibonacci数列吗!!!
在32位范围内不就只有不到50个数吗,发现这个之后这题就好办了~
即我们只要爆搜小于50次就能找到答案
补充一点小优化~
- 计算前缀和可以边读入边累加
- 特判一:如果读入的数恰好等于m就直接输出m并退出
- 特判二:如果读入的数大于了m就把他删去,并要:
-
在前缀和里面去掉
-
a[i]:=0;
-
因为读入是递增的所以直接退出循环并将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
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
根据题目条件:
并且,这一行中从第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 条评论