您的位置:首页 > 其它

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;
}


哇!又是一道很涨姿势的搜索题啊,记得以前第一次写那个在迷宫取钥匙用二进制进行状态压缩,也是一脸懵比啊,这次来一个状态哈希(自己编的名字

)?估计是水题刷多了,思维就比较局限了

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  BFS 搜索 思维