题目链接:https://vijos.org/p/1159

    https://www.luogu.org/problem/show?pid=1494

这是今天的第三道迭代深搜的题,虽然都是迭代深搜的模板,都是一些基础题,但是还是觉得自己不行啊。。。

拿到题目后我就有了一个大胆的想法[vijos1159&洛谷1494]岳麓山上打水<迭代深搜>-LMLPHP

然后自己仔细斟酌之后我就pass了他。。。我原本想在dfs中来记录下有几种水桶,现在询问的是哪一个水桶,当前这个水桶选了几个。。。

然而,这个想法实在是太大胆了。。。。。。。在一番斟酌之后,我想到了一个神奇的东西叫记忆化搜索。。

[vijos1159&洛谷1494]岳麓山上打水<迭代深搜>-LMLPHP

这是神奇海螺告诉我的。。。对,没错,就是这个记忆化搜索。。。。

【思路】

记忆化的时候开一个数组f,f[i]表示水量i的时候能不能让水装满(或者说能不能满足题的条件),如果i能够减去我选出来的水桶并让肛♂里的水变成0.说明这个是可行滴

这也是这题里唯一需要注意的地方,这个记忆化处理实质上就是判断你选出的数能不能让水缸的水被桶接完

假如你只选了水桶3,水量变化16-13-10-7-4-1-狗带

假如选了水桶3和5,水量变化16-13-10-5-5-因吹斯听

可能这个地方有点抽象,所以要多多理解一下。。。。。。

 #include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<vector>
#include<cmath>
#define maxn 20005
#define maxm 105
using namespace std; int v,m,ans,val[maxm],flag,a[maxm],f[maxn]; int comp(const void*a,const void*b)
{
return(*(int*)a)>(*(int*)b)?:-;
} int check(int n)
{
if(n==)return f[n]=;//如果可以把水装走
if(f[n]!=-)return f[n];//如果之前已经试过这么多水能不能装走
for(int i=;i<=ans;i++)
{
if(n>=a[i]&&check(n-a[i]))
return f[n]=;//成功装走,记录路径
}
return f[n]=;
} void dfs(int num,int sum)//第几种,有几种
{
if(sum==ans+)
{
memset(f,-,sizeof(f));
if(check(v))
{
flag=;
return ;
}
return;
}
if(flag==||num>m)return ;
a[sum]=val[num];
dfs(num+,sum+);//选第num个桶
dfs(num+,sum);//不选第num个桶,在接下来覆盖这一位
} int main()
{
scanf("%d%d",&v,&m);
for(int i=;i<=m;i++)
{
scanf("%d",&val[i]);
}
qsort(val,m+,sizeof(int),comp);
if(val[]==){
printf("1 1");return ;
}else{ for(ans=;ans<=m;ans++)
{
dfs(,);
if(flag){
printf("%d ",ans);
for(int i=;i<=ans;i++)
printf("%d ",a[i]);
return ;
}
} }
}

小小总结:我记得我学迭代深搜的时候,是和着记忆化一起学的,然后从今天的几道题看,迭代深搜经常会和记忆化一起出现。。。以后做题的时候可以多往这个方向想,而不是一些大胆的想法

05-11 17:13