UVALive-7354-Kitchen Measurements(BFS搜索)

来源:互联网 发布:mac双系统 没了一个 编辑:程序博客网 时间:2024/05/29 08:52

题目链接:点击打开链接

题目大意:
给定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 longusing 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;}

哇!又是一道很涨姿势的搜索题啊,记得以前第一次写那个在迷宫取钥匙用二进制进行状态压缩,也是一脸懵比啊,这次来一个状态哈希(自己编的名字大笑)?估计是水题刷多了,思维就比较局限了哭