一道hash题

Description

 春天到了,百花齐放,西湖公园里新设置了许多花坛,设计师想用不同的花摆出不同的图案以吸引游人,于是设计了各种图案并且在花圃中选好了要摆放的花。不幸的是负责搬运和摆放的工人因为临时有事,只将花放到花架上就匆匆离开了,并没有按照设计师原来的设计方案摆放,结果花坛杂乱不堪,设计师只好自己来调整花的位置。由于设计师通常从事脑力劳动,较少从事搬运和摆放花盆的体力工作,所以请你帮忙找出一种移动方法使工作量最小。

  不同种类的花有不同的类型编号,虽然地球上花的种类很多,但因为公园里的花不超过1,000,000种,所以花的类型编号不超过1,000,000。另一方面,出于美学考虑,一个花坛里摆放的不同种类的花不超过3种,且不同种类的花的数量不可太接近,对于任意两种花,数量多的花的盆数至少是数量少的花的2倍。

  花坛是正六边形的,共摆放有19盆花,每盆花都放在一个转盘上,转动一盆花下面的转盘,会使周围的6盆花顺时针或逆时针移动一个位置(但不可把花转到花坛外),称为一次操作。你的任务:用最少的操作使花坛由初始状态转化为符合设计图纸的目标状态。 例如:
这里写图片描述

初始状态              目标状态

  如图,只需将处于圆心位置的那盆花的转盘顺时针转动一个位置,红色的花就移动到了目标位置。

Input Format

 输入文件共11行,1-5行描述花坛的初始状态,7-11行表示花盆应摆放的位置。中间以空行分隔。5行数字分别表示花坛的5个行,其中第1、5两行有3个整数,第2、4两行有4个整数,第3行有5个整数,表示每一行的花的类型,不同的数代表不同种类的花。

Output Format

输出文件第一行包含一个整数T即最少的操作数,数据保证20步之内有解。以下T行输出操作序列,每行代表一次操作,包括3个整数 , , ,( , )表示第i步转动第 行,第 盆花下的转盘,当 为0时表示向顺时针方向转动, 为1时表示向逆时针方向转动,如有多种方案,任意输出其中一种即可。

Sample Input
1 1 1
1 2 1 1
1 1 1 1 1
1 1 1 1
1 1 1

1 1 1
1 1 1 1
1 1 2 1 1
1 1 1 1
1 1 1

Sample Output
1
3 2 0

思路:很明显这是一道广搜题,但如果是普通的搜,就会超时。
我们可以发现,在广搜的时候,会搜到很多重复的状态,因此多了很多的时间复杂度,那么我们可以将这些状态存下来,然后在搜索的时候判断是否搜过,便能减少很多复杂度。
这里介绍一种处理方法:hash。
就是根据数字的特征去存储数据,这样查找起来方便,特别对于大数字但是数据量少的时候,就格外好用(类似于离散化)
但是坑爹的是,这道题普通的hash还过不了。必须要加上链表优化。
我们在普通hash的时候,若这一位有用过,那么就单纯的+1就好了。
这样显然会很慢。那么我们就通过一种链表的方法:把同余的点连起来,那么我们在查找这个点是否被存过的时候,就非常快。
ps:这题的状态用3进制表示起来更加省空间,不然会爆空间的样子233

    #include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<algorithm>
#include<stack>
#define N 1300000
#define MOD 806871
typedef long long LL;
struct aa{
    int x,id;
}c[21];
int yz[21],mz[21],b[9],next[N],tou[N],head,tail,bs[N];
LL q[N],cs,mb;
bool cmp(aa x,aa y){return x.x<y.x;}
void ha(LL x){
    int j=x%MOD;
    if (!tou[j]){
        tou[j]=tail+1;
        q[++tail]=x;
        bs[tail]=bs[head]+1;
        return;
    } 
    int last;
    j=tou[j];
    while (j){
        if (q[j]==x)return;
        last=j;
        j=next[j];
    }
    next[last]=tail+1;
    q[++tail]=x;
    bs[tail]=bs[head]+1;
    return;
}
LL rturn(int x,int zt){
    LL sta=q[zt];
    int bz[29];
    for (int i=19;i>=1;i--)bz[i]=sta%3,sta/=3;
    if (x==5||x==6){
        int p=bz[x-4];
        bz[x-4]=bz[x-1];bz[x-1]=bz[x+4];bz[x+4]=bz[x+5];bz[x+5]=bz[x+1];bz[x+1]=bz[x-3];bz[x-3]=p;
        LL xx=0;
        for (int i=1;i<=19;i++) xx=xx*3+bz[i];
        return xx;
    }
    if (x==9||x==10||x==11){
        int p=bz[x-5];
        bz[x-5]=bz[x-1];bz[x-1]=bz[x+4];bz[x+4]=bz[x+5];bz[x+5]=bz[x+1];bz[x+1]=bz[x-4];bz[x-4]=p;
        LL xx=0;
        for (int i=1;i<=19;i++) xx=xx*3+bz[i];
        return xx;
    }
    if (x==14||x==15){
        int p=bz[x-5];
        bz[x-5]=bz[x-1];bz[x-1]=bz[x+3];bz[x+3]=bz[x+4];bz[x+4]=bz[x+1];bz[x+1]=bz[x-4];bz[x-4]=p;
        LL xx=0;
        for (int i=1;i<=19;i++) xx=xx*3+bz[i];
        return xx;
    }
    return 0;
}
LL lturn(int x,int zt){
    LL sta=q[zt];
    int bz[29];
    for (int i=19;i>=1;i--)bz[i]=sta%3,sta/=3;
    if (x==5||x==6){
        int p=bz[x-1];
        bz[x-1]=bz[x-4];bz[x-4]=bz[x-3];bz[x-3]=bz[x+1];bz[x+1]=bz[x+5];bz[x+5]=bz[x+4];bz[x+4]=p;
        LL xx=0;
        for (int i=1;i<=19;i++) xx=xx*3+bz[i];
        return xx;
    }
    if (x==9||x==10||x==11){
        int p=bz[x-1];
        bz[x-1]=bz[x-5];bz[x-5]=bz[x-4];bz[x-4]=bz[x+1];bz[x+1]=bz[x+5];bz[x+5]=bz[x+4];bz[x+4]=p;
        LL xx=0;
        for (int i=1;i<=19;i++) xx=xx*3+bz[i];
        return xx;
    }
    if (x==14||x==15){
        int p=bz[x-1];
        bz[x-1]=bz[x-5];bz[x-5]=bz[x-4];bz[x-4]=bz[x+1];bz[x+1]=bz[x+4];bz[x+4]=bz[x+3];bz[x+3]=p;
        LL xx=0;
        for (int i=1;i<=19;i++) xx=xx*3+bz[i];
        return xx;
    }
    return 0;
}
void bfs(LL x){
    head=0;tail=0;
    ha(x);
    while (head<=tail){
        head++;
        for (int i=1;i<=7;i++){
            LL ls=lturn(b[i],head);
            ha(ls);
            if (ls==mb){
                printf("%d\n",bs[tail]);
                exit(0);
            }
            LL rs=rturn(b[i],head);
            ha(rs);
            if (rs==mb){
                printf("%d\n",bs[tail]);
                exit(0);
            }
        }
    }
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("flowers.in","r",stdin);
    freopen("flowers.out","w",stdout);
    #endif
    for (int i=1;i<=19;i++)scanf("%d",&c[i].x),c[i].id=i;
    std::sort(c+1,c+20,cmp);
    bs[0]=-1;
    int j=-1;
    c[0].x=-1;;
    for (int i=1;i<=19;i++)
      if (c[i].x!=c[i-1].x)yz[c[i].id]=++j;else yz[c[i].id]=j;
    for (int i=1;i<=19;i++)scanf("%d",&c[i].x),c[i].id=i;
    std::sort(c+1,c+20,cmp);
    b[1]=5;b[2]=6;b[3]=9;b[4]=10;b[5]=11;b[6]=14;b[7]=15;
    j=-1;
    for (int i=1;i<=19;i++)
    if (c[i].x!=c[i-1].x)mz[c[i].id]=++j;else mz[c[i].id]=j;
    for (int i=1;i<=19;i++)cs=cs*3+yz[i];
    for (int i=1;i<=19;i++)mb=mb*3+mz[i];
    if (cs==mb){
        printf("0");
        return 0;
    }
    bfs(cs);
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值