Mayan游戏

题面:https://www.luogu.org/problemnew/show/P1312

搜索无疑

剪枝:

1.交换的两个块颜色相同,跳过。

2.如果一个块的左边有块,那么这个块左移不优。

因为左边的这个块右移效果相同,但是字典序更优。

我的剪枝:
1.如果一个颜色的块>=1且<=2,return

2.如果一种颜色的相邻距离-1的和>剩下步数,return(因为,一次操作,最多一个块进行靠拢)

3.哈希表判重

 

代码:

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int P=16;
const int mo=1e5;
const int M=800000+5;
int mp[10][8];
int n;
bool kp;
int up=0;
struct ha{
    int cnt;
    ll val[M],nxt[M];
    int hd[mo];
    void ins(ll x){
        int pos=x%mo;
        val[++cnt]=x;nxt[cnt]=hd[pos];hd[pos]=cnt;
    }
    bool query(ll x){
        int pos=x%mo;
        for(int i=hd[pos];i;i=nxt[i]){
            if(val[i]==x) return true;
        }return false;
    }
}HA;
void down(){
    for(int j=1;j<=5;j++){
        int top=1;
        for(int i=1;i<=7;i++){
            if(mp[i][j]){
                if(top!=i) mp[top][j]=mp[i][j],mp[i][j]=0;
                ++top;
            }
        }
    }
}
bool die[10][8];
bool kil(bool oo){
    memset(die,0,sizeof die);
    for(int j=1;j<=5;j++){
        int co=0;
        int cnt=0;
        int st=0;
        for(int i=1;i<=7;i++){
            co=mp[i][j];
            st=i;
            cnt=0;
            while(i<=7&&mp[i][j]==co) cnt++,i++;
            i--;
            if(cnt>=3&&co){
                for(int k=st;k<=i;k++) die[k][j]=1;
            }
        }
    }
    for(int i=1;i<=7;i++){
        int co=0;
        int cnt=0;
        int st=0;
        for(int j=1;j<=5;j++){
            co=mp[i][j];
            st=j;
            cnt=0;
            while(j<=5&&mp[i][j]==co) cnt++,j++;
            j--;
            if(cnt>=3&&co){
                for(int k=st;k<=j;k++) die[i][k]=1;
            }
        }
    }
    bool over=false;
    for(int i=1;i<=7;i++){
        for(int j=1;j<=5;j++){
            if(die[i][j]){
                over=true;
                mp[i][j]=0;
            }
        }
    }
    if(over) return true;
    return false;
}
struct node{
    int x,y,d;
}sta[10],ans[10];
int top;
bool fl;
int las[P];
int nd[P];
int num[P];
int che(int re){
    memset(las,0,sizeof las);
    memset(nd,0,sizeof nd);
    memset(num,0,sizeof num);
    ll hsh=re;
    int sz=0;
    for(int j=1;j<=5;j++){
        for(int i=1;i<=7;i++){
            hsh=(hsh*P+mp[i][j])%mod;
            if(mp[i][j]==0) break;
            sz++;
            num[mp[i][j]]++;
            if(las[mp[i][j]]){
                nd[mp[i][j]]+=j-las[mp[i][j]]-1;
            }
            las[mp[i][j]]=j;
        }
    }
    if(sz==0) return 2;
    if(HA.query(hsh)) return 0;
    for(int c=1;c<=up;c++){
        if(nd[c]>re) return 0;
        if(num[c]==1||num[c]==2) return 0;
    }
    HA.ins(hsh);
    return 1;
}
bool cmp(){
    for(int i=1;i<=n;i++){
        if(sta[i].y<ans[i].y) return true;
        if(sta[i].y>ans[i].y) return false;
        if(sta[i].x<ans[i].x) return true;
        if(sta[i].x>ans[i].x) return false;
        if(sta[i].d>ans[i].d) return true;
        if(sta[i].d<ans[i].d) return false;
    }
    return false;
}
int shit=0;
void dfs(int now){
    if(now==n+1){
        if(che(0)==2){
            if(!fl){
                fl=true;
                for(int i=1;i<=n;i++){
                    ans[i]=sta[i];
                }
            }
            else if(cmp()){
                for(int i=1;i<=n;i++){
                    ans[i]=sta[i];
                }
            }
        }    
        return;    
    }
    if(!che(n-now+1)) return;
    int tmp[10][8];
    memcpy(tmp,mp,sizeof mp);
    for(int j=1;j<=5;j++){
        for(int i=1;i<=7;i++){
            if(mp[i][j]){
                if(j!=1&&mp[i][j]!=mp[i][j-1]&&(!mp[i][j-1])){
                    swap(mp[i][j],mp[i][j-1]);
                    sta[now].x=i,sta[now].y=j;
                    sta[now].d=-1;
                    while(1){
                        down();
                        if(!kil(kp)) break;
                    }
                    dfs(now+1);
                    sta[now].x=sta[now].y=sta[now].d=0;
                    memcpy(mp,tmp,sizeof tmp);
                }
                
                if(j!=5&&mp[i][j]!=mp[i][j+1]){
                    swap(mp[i][j],mp[i][j+1]);
                    sta[now].x=i,sta[now].y=j;
                    sta[now].d=1;
                    while(1){
                        down();
                        if(!kil(kp)) break;
                    }
                    dfs(now+1);
                    sta[now].x=sta[now].y=sta[now].d=0;
                    memcpy(mp,tmp,sizeof tmp);
                }
                
            }
            else break;
            
        }
    }
}
int main(){
    scanf("%d",&n);
    for(int j=1;j<=5;j++){
        int lp=0;
        int t;
        while(1){
            scanf("%d",&t);
            up=max(up,t);
            if(t==0) break;
            mp[++lp][j]=t;
        }
    }
    fl=false;
    dfs(1);
    if(!fl){
        printf("-1");return 0;
    }
    for(int i=1;i<=n;i++){
        printf("%d %d %d\n",ans[i].y-1,ans[i].x-1,ans[i].d);
    }
    return 0;
}

 错误点:

1.消除的时候中途出锅

2.HA表,必须再加上剩余步数作为hash值,否则会把正解冲突。

3.关键字的比较!我用的是x,y翻过来的情况,所以,程序中,应该先比较y,再比较x。

 

总结:
搜索这种东西,细节就是极多,写的时候一定要头脑清醒,不可大意。

而且,过多的递归,很难调试。

转载于:https://www.cnblogs.com/Miracevin/p/9779642.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值