样例不过求条 玄4关
查看原帖
样例不过求条 玄4关
1073342
Genshin_ZFYX楼主2025/2/4 21:39

剪枝,按照蓝书上写的,一大堆史错误,调了几天了

#include<bits/stdc++.h>
using namespace std;
//#define int long long
const int n=16;
int a[n+5][n+5],b[n+5],l[n+5],h[n+5],g[n+5][n+5],lg[10000005];
//a为数独,b为每个九宫格的状态,l为每一行的状态,h为每一列的状态,g为每个格子所在的九宫格,lg为log2
int lf[n+5][n+5],hf[n+5][n+5],bf[n+5][n+5],ln[n+5][n+5][2],hn[n+5][n+5][2],bn[n+5][n+5][2];
//lf[i][j],hf[i][j],bf[i][j]表示在第i行/i列/i宫中有多少个位置可以填j
//ln[i][j][0],ln[i][j][1],hn[i][j][0],hn[i][j][1],bn[i][j][0],bn[i][j][1]表示在第i行/i列/i宫中j的可以填的最后一个位置
//在dfs中,如果有一个位置只能填一个数,那么就填上去,然后把这个位置的行列宫的状态更新,ln,hn,bn用来记录这个位置的行列宫
inline void A(int x,int y,int t,bool f)
{
    if(f)l[x]|=t;
    else if((l[x]^t)<l[x])l[x]^=t;
    else cout<<"error"<<endl;//调试输出错误,为了方便差错,见120行
    
    if(f)h[y]|=t;
    else if((h[y]^t)<h[y])h[y]^=t;
    else cout<<"error"<<endl;

    if(f)b[g[x][y]]|=t;
    else if((b[g[x][y]]^t)<b[g[x][y]])b[g[x][y]]^=t;
    else cout<<"error"<<endl;
}
bool f;
void dfs(int x,int y)
{
    if(f)return;
    //调试,输出当前状态,cph存不下就只选了x=11的情况
    if(x==0&&y==0)
    {
        f=1;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
                cout<<(char)(a[i][j]+'A'-1);
            cout<<endl;
        }
        return;
    }
    int nx=0,ny=0,minn=114514;
    vector<int>vx,vy;
    vx.clear();vy.clear();
    //初始化是必须的,有时候提前剪枝回溯了,但是状态没有更新
    memset(lf,0,sizeof(lf));
    memset(hf,0,sizeof(hf));
    memset(bf,0,sizeof(bf));
    //下面这三行好像没用
    memset(ln,0,sizeof(ln));
    memset(hn,0,sizeof(hn));
    memset(bn,0,sizeof(bn));
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    {
        if(a[i][j])
        {
            //如果这个位置已经填了,那么就更新行列宫的状态
            //在循环剪枝时不会return
            lf[i][a[i][j]]=2;
            hf[j][a[i][j]]=2;
            bf[g[i][j]][a[i][j]]=2;
            continue;
        }
        int cnt=0;
        int S=l[i]&h[j]&b[g[i][j]];
        if(S==0)
        {
            //一个数也填不了,回溯
            for(int i=0;i<(int)vx.size();i++)
            {
                A(vx[i],vy[i],1<<a[vx[i]][vy[i]],1);
                a[vx[i]][vy[i]]=0;
            }
            return;
        }
        while(S)
        {
            int t=S&(-S);
            S-=t;
            //更新行列宫的状态
            cnt++;
            lf[i][lg[t]]++;
            hf[j][lg[t]]++;
            bf[g[i][j]][lg[t]]++;
            ln[i][lg[t]][0]=i;ln[i][lg[t]][1]=j;
            hn[j][lg[t]][0]=i;hn[j][lg[t]][1]=j;
            bn[g[i][j]][lg[t]][0]=i;bn[g[i][j]][lg[t]][1]=j;
        }
        if(i==x&&j==y)continue;//跳过
        //只能填一个数,立刻填上去
        if(cnt==1){
            int t=l[i]&h[j]&b[g[i][j]];
            A(i,j,t,0);
            a[i][j]=lg[t];
            vx.push_back(i);
            vy.push_back(j);
        }
        else if(cnt<minn)
        {
            minn=cnt;
            nx=i;
            ny=j;
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            //这里没有一个可以填的位置,那么就回溯
            if(lf[i][j]==0||hf[i][j]==0||bf[i][j]==0)
            {
                lf[i][j]=hf[i][j]=bf[i][j]=0;
                for(int i=0;i<(int)vx.size();i++)
                {
                    A(vx[i],vy[i],1<<a[vx[i]][vy[i]],1);
                    a[vx[i]][vy[i]]=0;
                }
                return;
            }
            //下面这段去掉会超时,加上会出现error
            // if(lf[i][j]==1&&a[ln[i][j][0]][ln[i][j][1]]==0)
            // {
            //     a[ln[i][j][0]][ln[i][j][1]]=j;
            //     A(ln[i][j][0],ln[i][j][1],1<<j,0);
            //     vx.push_back(ln[i][j][0]);
            //     vy.push_back(ln[i][j][1]);
            // }
            // if(hf[i][j]==1&&a[hn[i][j][0]][hn[i][j][1]]==0)
            // {
            //     a[hn[i][j][0]][hn[i][j][1]]=j;
            //     A(hn[i][j][0],hn[i][j][1],1<<j,0);
            //     vx.push_back(hn[i][j][0]);
            //     vy.push_back(hn[i][j][1]);
            // }
            // if(bf[i][j]==1&&a[bn[i][j][0]][bn[i][j][1]]==0)
            // {
            //     a[bn[i][j][0]][bn[i][j][1]]=j;
            //     A(bn[i][j][0],bn[i][j][1],1<<j,0);
            //     vx.push_back(bn[i][j][0]);
            //     vy.push_back(bn[i][j][1]);
            // }
        }
    }
    int S=l[x]&h[y]&b[g[x][y]];
    while(S)
    {
        int t=S&(-S);
        S^=t;
        a[x][y]=lg[t];
        A(x,y,t,0);
        dfs(nx,ny);
        A(x,y,t,1);
        a[x][y]=0;
    }
    for(int i=0;i<(int)vx.size();i++)
    {
        A(vx[i],vy[i],1<<a[vx[i]][vy[i]],1);
        a[vx[i]][vy[i]]=0;
    }
    return;
}
signed main()
{
    cin.tie(0)->sync_with_stdio(0);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            g[i][j]=(i-1)/4*4+(j-1)/4+1;
    for(int i=1;i<=n;i++)lg[1<<i]=i;
    // string s;
    int T;cin>>T;
    while(T--)
    {
        // if(s=="end")break;
        for(int i=1;i<=n;i++)
        {
            b[i]=l[i]=h[i]=0;
            for(int j=1;j<=n;j++)
                {
                    b[i]|=1<<j;
                    l[i]|=1<<j;
                    h[i]|=1<<j;
                }
        }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                char c;cin>>c;
                if(c=='-')a[i][j]=0;
                else a[i][j]=c-'A'+1;
                if(a[i][j])
                {
                    l[i]^=1<<a[i][j];
                    h[j]^=1<<a[i][j];
                    b[g[i][j]]^=1<<a[i][j];
                }
            }
        f=0;
        dfs(1,1);
        //中间输出不出来,只能输出最后的结果看看有没有回溯完
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
                if(a[i][j])cout<<(char)(a[i][j]+'A'-1);
                else cout<<'-';
            cout<<endl;
        }
        // cout<<"end";
    }
    return 0;
}

2025/2/4 21:39
加载中...