bzoj5156 [Tjoi2014]拼图(状压+爆搜)

本文介绍了一种使用状态压缩技术的搜索算法实现方法,通过压缩每个位置的状态来提高搜索效率。文章详细解释了如何利用位操作进行状态表示,并通过具体实例展示了如何避免重复状态以及输出可能的解。此外,还讨论了输出格式的细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

应该直接爆搜就可以了。我状压了一下每个位置目前是否被占据,跑得快了一些。不过这样输出路径时有点麻烦x
注意输出的,后面有空格。。。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 20
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,r[N],c[N],mp[N],id[5][5],bin[20],ans,a[N];
char s[N],res[5][5],f[N];
inline bool cmp(int a,int b){return mp[a]>mp[b];}
void dfs(int cntt,int S){
    if(cntt>n){ans++;return;}int cnt=a[cntt];
    for(int i=0;i<=4-c[cnt];++i)
        for(int j=0;j<=4-r[cnt];++j){
            int ss=(mp[cnt]<<i+4*j)&(bin[16]-1);
            if(ss&S) continue;dfs(cntt+1,S|ss);
            if(!f[cnt]&&ans>=1){
                f[cnt]=1;
                for(int x=0;x<r[cnt];++x)
                    for(int y=0;y<c[cnt];++y)
                        if(mp[cnt]&bin[id[x][y]])
                            res[x+j][y+i]=cnt+'0';
            }if(ans==2) return;
        }
}
int main(){
    int num=-1;bin[0]=1;
    for(int i=1;i<=16;++i) bin[i]=bin[i-1]<<1;
    for(int i=0;i<4;++i)
        for(int j=0;j<4;++j) id[i][j]=++num;
    while(~scanf("%d",&n)){
        int tot=0;bool flag=1;ans=0;memset(f,0,sizeof(f));
        for(int i=1;i<=n;++i){
            r[i]=read();c[i]=read();if(r[i]>4||c[i]>4) flag=0;mp[i]=0;
            for(int j=0;j<r[i];++j){
                scanf("%s",s);if(!flag) continue;
                for(int k=0;k<c[i];++k)
                    if(s[k]=='1') ++tot,mp[i]|=bin[id[j][k]];
            }
        }if(tot!=16||!flag){puts("No solution");continue;}
        for(int i=1;i<=n;++i) a[i]=i;sort(a+1,a+n+1,cmp);
        dfs(1,0);if(!ans){puts("No solution");continue;}
        if(ans==2){puts("Yes, many!");continue;}puts("Yes, only one!");
        for(int i=0;i<4;++i) puts(res[i]);
    }return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值