这道题以前我也遇见过,但是没搞明白,现在搞明白了:
这道题我当时一读题就想用dfs,但是有个问题就是我怎么把n-1个空位插k个乘号进去,并且最终判断最大值,因为dfs是要对每个位置都要枚举,并且前面的位置要占满;所以我就一直在想这个问题,结果没想出来,之后百度了一下,看了其他人的dfs,我感觉,那些人是真的大佬,我好菜。最后我还是看明白了,代码中count表示填的乘号的个数,res表示上几次段的数的乘积,index表示当前插入的下标,可以这样理解:
有了这个图才好理解下面说的话:
如果我要插入多个乘号,那么第一个乘号的范围就是[1,n-1],然后第二个乘号的范围就应该是[1,n],但是因为第二个的下限要受到第一个的制约,所以他本来的下限就应该是第一个的index+1;然后多个也照样这样理解;
现在的问题就是如何去把空位里面找出所有可能的填上k个乘号的填法,并且让每种填法比较;这里就需要知道这个问题:
因为dfs是对无间隙的遍历,且有一定范围;所以可以不难知道:每次遍历的范围是在[index+1,n-k+count];这里可以用笔算一下
这样每次dfs的时候只需要把前面的范围的值算出来之后传递给后面的dfs就可以解决这个问题了;如果仔细用脑袋想一下,也应该是这样的(把每次放置的位置所隔开的数都算出来,然后dfs(这个想法我挺佩服那些大佬的));
所以按照这种思路dfs就OK了:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll book[1000];
ll n,k,Max;
string s;
ll a[100];
void dfs(ll count,ll res,ll index){
if(count==k){//当填够k个的时候
ll num=0;
for(int i=index+1;i<=n;i++){//计算余下的数(如果越界就表示没有)
num=num*10+a[i];
}
Max=max(Max,res*num);
return ;
}
for(int i=index+1;i<=n-k+count;i++){//这里就是上面说的每个能走到的最大下标(当然如果越界了就不会计算下面的了)
ll num=0;
for(int j=index+1;j<=i;j++){//这里就是把分段的可能性都计算(一个dfs一个可能性)
num=num*10+a[j];
}
dfs(count+1,res*num,i);//这里是把上回的分段结果乘上res传给下一个dfs
}
}
int main(){
scanf("%lld %lld",&n,&k);
cin>>s;
for(int i=0;i<s.length();i++) a[i+1]=s[i]-'0';//这里初始化下标是从1开始的!!!
dfs(0,1,0);//表示还没有填res=1是为了后面的计算
printf("%lld\n",Max);
return 0;
}