专栏文章

用深搜解决P1043

P1043题解参与者 4已保存评论 4

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
4 条
当前快照
1 份
快照标识符
@mipns9ea
此快照首次捕获于
2025/12/03 15:01
3 个月前
此快照最后确认于
2025/12/03 15:01
3 个月前
查看原文
经过本蒟蒻无数次的提交,我用深搜 AC 这道题了!

解题思路

我们可以把写 22 个深搜,分别用来求最大值和最小值。设 dfs(id,last)dfs(id,last) 表示现在要处理第 idid 个数,上一个数字是放在第 lastlast 个区块里面。那么,我们就可以很轻松地写出程序了。但是有个细节,如果 step=nstep=n,他也可以放在第 11 个区块,因为他是一个环形的。
这个程序虽然会超时,但是只有第 44 个数据超时了,也能获得 8080 分的好成绩。
CPP
#include<bits/stdc++.h>
using namespace std;
int n,m,a[51],sum[10],ans_max=INT_MIN,ans_min=INT_MAX;
bool flag[10];
int mod10(int x)
{
	return ((x%10)+10)%10;
}
void dfs1(int id,int last)
{
	int ans=1;
	for(int i=1;i<=m;i++)
	{
		if(flag[i])
		{
			ans*=mod10(sum[i]);
		}
	}
	if(id==n+1)
	{
		if(sum[m]!=0)
		ans_min=min(ans_min,ans);
		return;
	}
	if(id==1)
	{
		flag[1]=true;
		sum[1]=a[1];
		dfs1(2,1);
	}
	else
	{
		sum[last]+=a[id];
		dfs1(id+1,last);
		sum[last]-=a[id];
		if((last+1)<=m)
		{
			sum[last+1]+=a[id];
			flag[last+1]=true;
			dfs1(id+1,last+1);
			sum[last+1]-=a[id];
			flag[last+1]=false;
		}
		if(id==n)
		{
			sum[1]+=a[n];
			dfs1(n+1,1);
			sum[1]-=a[n];
		}
	}
}
void dfs2(int id,int last)
{
	int ans=1;
	for(int i=1;i<=m;i++)
	{
		if(flag[i])
		{
			ans*=mod10(sum[i]);
		}
	}
	if(id==n+1)
	{
		if(sum[m]!=0)
		ans_max=max(ans_max,ans);
		return;
	}
	if(id==1)
	{
		flag[1]=true;
		sum[1]=a[1];
		dfs2(2,1);
	}
	else
	{
		sum[last]+=a[id];
		dfs2(id+1,last);
		sum[last]-=a[id];
		if((last+1)<=m)
		{
			sum[last+1]+=a[id];
			flag[last+1]=true;
			dfs2(id+1,last+1);
			sum[last+1]-=a[id];
			flag[last+1]=false;
		}
		if(id==n)
		{
			sum[1]+=a[n];
			dfs2(n+1,1);
			sum[1]-=a[n];
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	scanf("%d",&a[i]);
	dfs1(1,0);
	for(int i=1;i<=m;i++)
	{
		sum[i]=0;
		flag[i]=false;
	}
	dfs2(1,0);
	printf("%d\n%d",ans_min,ans_max);
	return 0;
}
最优性剪枝:求最大值时,如果当前的最优可能,也不如 ansmaxansmax,直接返回。最优可能是什么呢?就是把不确定的算出 99。要注意的是,第 lastlast 个要算成 99,因为它还没结束,只是开始了。第 11 个区块也要算成 99,因为它后面可能因第 nn 个数字而变化。当然,我们可以用同样的方法来对求最小值的深搜剪枝。
100100 分代码
CPP
#include<bits/stdc++.h>
using namespace std;
int n,m,a[51],sum[10],ans_max=INT_MIN,ans_min=INT_MAX;
bool flag[10];
int mod10(int x)
{
	return ((x%10)+10)%10;
}
void dfs1(int id,int last)
{
	int ans=1,cnt=1;
	for(int i=1;i<=m;i++)
	{
		if(flag[i])
		{
			if(i!=1&&i!=last)
			cnt*=mod10(sum[i]);
			ans*=mod10(sum[i]);
		}
	}
	if(cnt>=ans_min)
	return;
	if(id==n+1)
	{
		if(sum[m]!=0)
		ans_min=min(ans_min,ans);
		return;
	}
	if(id==1)
	{
		flag[1]=true;
		sum[1]=a[1];
		dfs1(2,1);
	}
	else
	{
		sum[last]+=a[id];
		dfs1(id+1,last);
		sum[last]-=a[id];
		if((last+1)<=m)
		{
			sum[last+1]+=a[id];
			flag[last+1]=true;
			dfs1(id+1,last+1);
			sum[last+1]-=a[id];
			flag[last+1]=false;
		}
		if(id==n)
		{
			sum[1]+=a[n];
			dfs1(n+1,1);
			sum[1]-=a[n];
		}
	}
}
void dfs2(int id,int last)
{
	int ans=1,cnt=1;
	for(int i=1;i<=m;i++)
	{
		if(flag[i])
		ans*=mod10(sum[i]);	
	}
	for(int i=1;i<=m;i++)
	{
		if(i==1||flag[i]==false||i==last)
		cnt*=9;
		else
		cnt*=mod10(sum[i]);
	}
	if(cnt<=ans_max)
	return;
	if(id==n+1)
	{
		if(sum[m]!=0)
		ans_max=max(ans_max,ans);
		return;
	}
	if(id==1)
	{
		flag[1]=true;
		sum[1]=a[1];
		dfs2(2,1);
	}
	else
	{
		sum[last]+=a[id];
		dfs2(id+1,last);
		sum[last]-=a[id];
		if((last+1)<=m)
		{
			sum[last+1]+=a[id];
			flag[last+1]=true;
			dfs2(id+1,last+1);
			sum[last+1]-=a[id];
			flag[last+1]=false;
		}
		if(id==n)
		{
			sum[1]+=a[n];
			dfs2(n+1,1);
			sum[1]-=a[n];
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	scanf("%d",&a[i]);
	dfs1(1,0);
	for(int i=1;i<=m;i++)
	{
		sum[i]=0;
		flag[i]=false;
	}
	dfs2(1,0);
	printf("%d\n%d",ans_min,ans_max);
	return 0;
}

评论

4 条评论,欢迎与作者交流。

正在加载评论...