字符串不定求和 洛谷P1874题解

kkk大佬给出了思路,但没给出具体代码,题解里只有用P写的,所以这里我补充一个C党解法
传送门:
洛谷P1874
题目如下:
字符串不定求和 洛谷P1874题解_第1张图片
说实话我第一眼看这道题是很懵比了,看了题解更懵比,什么二维dp,什么深搜+剪枝…
各路神仙各显神通,身为蒟蒻的我战战兢兢,如履薄冰。在各路神仙的题解中,排行第一的是kkk大佬的一句话:
字符串不定求和 洛谷P1874题解_第2张图片
这种方法细想,确实妙哉。下面我们就聊聊这种想法。


把题目简化一下就是
输入一个数字字符串,问怎样组合使和为n。
例如:123456 如果它的组合方式是 1+2+3+45+6 就可以输出57 。但这道题反着来了,它先给出n(57)问你组合方式是怎样的。

把题目看到这里,本蒟蒻有了点想法:暴力枚举 ’ + ‘ 的位置,判断是否存在即可。
这个思路可行,但我不会代码实现啊!
这样写的困难在于,如何枚举位置?因为+的个数是不确定的,位置也是不确定的,如果暴力出奇迹要写很多代码(我太懒了 ACMer永不加班!)

所以核心问题就出来了:枚举出所有位置的值。

于是有大佬给出了这种想法:(绝妙的舞姿)

	for(int i=1;i<=str.length();i++)
	{
     
		f[i][i]=s[i];
		for(int j=i;j<=str.length()&&j-i<=11;j++)f[i][j]=f[i][j-1]*10+s[j];
	}

如果枚举所有位置很困难,为什么不分治成若干个位置呢?

本段代码的精髓就是用二维度数组实现了记忆位置并且存储了区间值。
那么之后我们只需要枚举一下所有情况即可。


利用搜索实现枚举

void dfs(int now,int befor,int sum,int t,int len)
{
     
	///cout<
	if(sum+f[befor][now]>n)return;
	if(now==len&&sum+f[befor][now]!=n)return;
	if(now==len&&sum+f[befor][now]==n)
	{
     minn=min(minn,t);return;} 
	dfs(now+1,now+1,sum+f[befor][now],t+1,len);
	dfs(now+1,befor,sum,t,len);
}

AC代码如下:

#include
using namespace std;
int n;
int minn=0x3f3f3f3f;
int f[45][45],s[45]; 
void dfs(int now,int befor,int sum,int t,int len)
{
     
	///cout<
	if(sum+f[befor][now]>n)return;
	if(now==len&&sum+f[befor][now]!=n)return;
	if(now==len&&sum+f[befor][now]==n)
	{
     minn=min(minn,t);return;} 
	dfs(now+1,now+1,sum+f[befor][now],t+1,len);
	dfs(now+1,befor,sum,t,len);
}
int main()
{
     
	ios::sync_with_stdio(false);
	string str;
	cin>>str;
	for(int i=0;i<str.length();i++)s[i+1]=str[i]-'0';
	for(int i=1;i<=str.length();i++)
	{
     
		f[i][i]=s[i];
		for(int j=i;j<=str.length()&&j-i<=11;j++)
		{
     
			f[i][j]=f[i][j-1]*10+s[j];
		}
	}
	cin>>n;
	dfs(1,1,0,0,str.length());
	if(minn==0x3f3f3f3f)cout<<-1<<endl;
	else cout<<minn<<endl;
	return 0;
 } 

你可能感兴趣的:(洛谷,算法)