UVALive-7354-Kitchen Measurements(BFS搜索)
2017-09-09 08:34
246 查看
题目链接:点击打开链接
题目大意:给定n(n<=5)个容积(v<=64)已知的杯子,体积从大到小,最开始最大的杯子是满的,给出最大体积杯子的目标状态,求:从初始状态到目标状态最少总共要倒多少单位体积的水。倒水的规则还是老规矩,总体积为每次倒水的体积和。
解题思路:
一:三个杯子的我们都写过,而这里最多有5个杯子,每个杯子的体积最大为64,用以前多维数组记录状态的方法就行不通了,然后我就GG了。
二:后面看了一下VJ上大佬们的代码,思路差不多是将每个状态进行hash,体积最多为64,那么将每一个状态hash成为一个65(64)进制的数,那么每个状态都可以唯一确定,不会有冲突,然后只要将hash,值解出来,就可以得到这个值对应的状态,看他们很多都用集合写的,然后我用queue()+map()TLE了(再一次Tmap)。
三:为什么要用map()?,因为对于一个状态hash()后,一个状态的hash值可以达到64^5级别,数组记录不了,而如果不这么hash的话又不好从hash值推出对应的状态。等等,既然这样,那么我们可以直接在每个结点都记录该节点对应的状态,然后只要保证一种不冲突而又可以用数组开下的hash方法就好了。不冲突,貌似进制数是能到的最简单的方法,但是上面提到了直接hash,数组开不下。其实再仔细想想,假如总共五个杯子,其中有四个杯子的状态已经确定了,那么最后一个杯子的状态也就确定了,该状态就是唯一确定的,而三个或者更少的就不能唯一确定状态,因为剩下的杯子的状态可以不唯一,所以我们可以只hash其中四个杯子,这样就只要开一个64^4级别的数组就可以记录状态了。
四:接下来就是正常的BFS()搜索了。
代码:
#include<iostream> #include<cstring> #include<string> #include<cstdio> #include<map> #include<queue> #include<set> #include<algorithm> #define LL long long using namespace std; int n,k,v[10],pre[10]; int mp[2*64*64*64*64+10]; struct node{ int val[10]; int tot; int hash_val; bool operator < (const node &n1)const{ return tot>n1.tot; } }beg,in,out; int Hash(int a[]){ int sum=0; for(int i=0;i<n-1;i++){ sum=sum*65+a[i]; } return sum; } void _copy(int a[],int b[]){ for(int i=0;i<n;i++){ a[i]=b[i]; } } int BFS(){ priority_queue<node>Q; Q.push(beg); while(!Q.empty()){ int ok=0; out=Q.top();Q.pop(); _copy(v,out.val); if(v[0]==k)return out.tot; for(int x=0;x<n;x++){ for(int y=0;y<n;y++){ if(x==y)continue; if(!v[x]&&!v[y])continue; int tmp=min(v[x],pre[y]-v[y]); if(tmp==0)continue; v[x]-=tmp; v[y]+=tmp; int has=Hash(v); _copy(in.val,v); v[x]+=tmp; v[y]-=tmp; in.tot=out.tot+tmp; if(mp[has]!=0&&mp[has]<=in.tot)continue; mp[has]=in.tot; in.hash_val=has; Q.push(in); } } } return -1; } int main(){ // freopen("in.txt","r",stdin); while(~scanf("%d",&n)){ memset(mp,0,sizeof mp); memset(pre,0,sizeof pre); memset(v,0,sizeof v); for(int i=0;i<n;i++)scanf("%d",&pre[i]); v[0]=pre[0]; scanf("%d",&k); beg.tot=0;beg.hash_val=Hash(v); beg.val[0]=pre[0]; mp[beg.hash_val]=-1; int ans=BFS(); if(ans==-1)printf("impossible\n"); else printf("%d\n",ans); } return 0; }
哇!又是一道很涨姿势的搜索题啊,记得以前第一次写那个在迷宫取钥匙用二进制进行状态压缩,也是一脸懵比啊,这次来一个状态哈希(自己编的名字
)?估计是水题刷多了,思维就比较局限了
。
相关文章推荐
- 搜索(DFS+BFS)——UVA Live 6455
- uvalive 3971 - Assemble(二分搜索 + 贪心)
- UVALive 3695 (博弈 bfs)
- UVa 11624 Fire!(搜索 -- BFS)
- UVALive 6255-状态搜索-Kingdoms
- UVALIVE 5893 计算几何+搜索
- UVALive - 7672 - What a Ridiculous Election(搜索预处理)
- UVA 1377 Ruler bfs+状压搜索
- UVa 11244 counting stars ( 搜索 BFS)
- UVALive 6888 Ricochet Robots bfs
- Regionals 2009 >> Asia - Hsinchu UVALIVE, 4529 A Constrained Queen Game - 搜索剪枝
- UVALive3902 Network[贪心 DFS&&BFS]
- UVA 11882 Biggest Number (dfs搜索+bfs 剪枝)
- UVALive-6665-Dragons Cruller(BFS+Hash)
- UVALive 6485 Electric Car Rally (BFS,优先队列)
- 例题1.8 彩色立方体 Colored Cubes UVALive - 3401 暴力打表+暴力搜索+贪心
- uvalive 5881 map + 搜索记录
- [状态搜索] UVa1601 The Morning after Halloween 普通BFS写法
- UVALive 7297 bfs
- UVALive 3667 Ruler(回溯搜索)