题目描述
给定 n(1<=n<=100)个互不相同的正整数 a1,a2,a3...an,将之排成一行(顺序)。再给你一个要求的值m(m<=1000)。你需要在每个 ai(ai<=100) 前加上一个加号(+)或减号(-),使这n个数字组成一个算式。请问是否存在一种添加符号的方案,使该算式的值为m?如果存在,请输出Yes,否则输出No。
例如,给定 n = 5, m = 17, a1 = 1, a2 = 4, a3 = 5, a4 = 9, a5 = 8,则 −a1 − a2 + a3 + a4 + a5 = 17。
解题思路
这道题目类型明显可以用深搜(DFS)来解决,因为每次添加的符号不是固定的(数据也很水),详见下图。
以题目中的例子为例
0(初始值)
+1 ans=1
继续执行...
-1 ans=-1
+4 ans=3
继续执行...
-4 ans=-5
+5 ans=0
+9 ans=9
+8 ans=17
!!这时候答案出现了,直接return,flag标记为真,这样程序会自动回溯,不必继续执行
-9 ans=-9
继续执行...
-5 ans=-10
继续执行...
相信很多初学搜索的人(包括蒟蒻我) 看着都很懵,其实这就是一个基本的二叉树,属于图论的一种,比较考验思维能力,形象来说就是不撞南墙不回头,对时间复杂度很友好(常数原则)。
代码实现
用dfs的深搜解决,可以每一次递归四次运算,求出结果就return 。
#include<bits/stdc++.h>
using namespace std;
int a[1005] {}, n,m;
bool flag = 0;
void dfs(int pos, int ans, int cnt)
{
if(cnt>n) { //符合条件就返回
if(ans == m) flag = 1; //标记
return;
}
dfs(pos+1,ans+a[pos],cnt+1); //递归两种运算
dfs(pos+1,ans-a[pos],cnt+1);
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i ++) cin >> a[i];
dfs(1,0,0);
puts(flag? "Yes":"No"); //判断标记
return 0;
}
这是一个很简单的深搜答案,但是还可以优化。
优化
return之后还要执行完其他的分支,比较费时间(不过一般不影响),这里介绍exit语句,可以直接在函数内结束程序,也可以做异常报告。
exit
语法格式
exit(返回值); //0的话直接结束,负数的话抛异常
比如下面这个例子,如果数组里有要找的数就直接输出并结束,省时间。
int a[1005]{},x; //数组和要找的数
//其他代码...
void find(int pos)
{
if(a[pos]==x) {
cout << pos << endl;
exit(0); //直接结束
}
find(pos+1); //继续找
}
在本例子里可能体现不出来,大家看深搜的代码就更有感受了。
//前面略
void dfs(int pos, int ans, int cnt)
{
if(cnt>n) { //符合条件就返回
if(ans == m) {
puts("Yes");
exit(0); //直接结束,省时间
}
return; //别忘了还要return
}
dfs(pos+1,ans+a[pos],cnt+1); //递归两种运算
dfs(pos+1,ans-a[pos],cnt+1);
}
int main()
{
//略...
return puts("NO"),0; //直接输出错,比之前省时间
}
拓展
这道题要求按照顺序添加符号,如果这道题要求可以改变顺序的话该怎么办呢?next_permutation函数!!!
next_permutation
语法格式
next_permutation(数组首地址,数组尾地址); //进行区间升序排列,如果全排完返回0,否则返回正值
那么代码就变成这样
#include<bits/stdc++.h>
using namespace std;
int a[1005] {}, n,m;
bool flag = 0;
void dfs(int pos, int ans, int cnt)
{
if(cnt>n) { //符合条件就返回
if(ans == m) {
puts("Yes");
exit(0); //直接结束,省时间
}
return; //别忘了还要return
}
dfs(pos+1,ans+a[pos],cnt+1); //递归四种运算
dfs(pos+1,ans-a[pos],cnt+1);
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i ++) cin >> a[i];
do{
dfs(1,0,0); //深搜
}while(next_permutation(a+1,a+n+1)); //不断排列
return puts("No"),0;
}
结束
今天的学习就到这里啦,一道简单的深搜应用题,希望大家能有收获!
掰掰ヾ(•ω•`)o
可以转载,请注明作者和原文链接

3万+

被折叠的 条评论
为什么被折叠?



