DLX SPOJ 1771 Yet Another N-Queen Problem (八皇后變形)

需要注意的有:

(1)行和列,斜線的hash

(2)搜的時候只用搜行列即可

(3)成功條件:d >=n 

(4)注意初始化!!!

???爲什麼白書的模板TLE???

網上模板ac:

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

const int maxnode = 55 * 55 * 4;
const int maxr = 55 * 55;
const int maxc = 55 * 6;

int U[maxnode],D[maxnode],L[maxnode],R[maxnode],C[maxnode],row[maxnode];
int H[maxr],S[maxc];
int ansd, ans[maxr];/// 注意初始化
int n,sz;
void init(int r,int c)
{
    for(int i=0; i<=c; ++i)
    {
        S[i]=0;
        U[i]=D[i]=i;
        L[i+1]=i;
        R[i]=i+1;
    }
    R[sz=c]=0;
    while(r)H[r--]=-1;
}
void remove(int c)
{
    L[R[c]]=L[c],R[L[c]]=R[c];
    for(int i=D[c]; i!=c; i=D[i])
        for(int j=R[i]; j!=i; j=R[j])
            U[D[j]]=U[j],D[U[j]]=D[j],--S[C[j]];
}
void resume(int c)
{
    L[R[c]]=R[L[c]]=c;
    for(int i=U[c]; i!=c; i=U[i])
        for(int j=L[i]; j!=i; j=L[j])
            ++S[C[U[D[j]]=D[U[j]]=j]];
}
bool Dance(int d)
{
    if(d>=n)
    {
        ansd = d;
        return 1;
    }
    if(!R[0])return 0;
    int c,tmp=maxnode;
    for(int i=R[0]; i; i=R[i])
        if(i<=n)
        {
            if(S[i]<tmp)tmp=S[c=i];
        }
        else break;
    remove(c);
    for(int i=D[c]; i!=c; i=D[i])
    {
        ans[d] = row[i];
        for(int j=R[i]; j!=i; j=R[j])remove(C[j]);
        if(Dance(d+1))return 1;
        for(int j=L[i]; j!=i; j=L[j])resume(C[j]);
    }
    resume(c);
    return 0;
}
void Link(int r,int c)
{
    ++S[C[++sz]=c];
    row[sz]=r;
    D[sz]=D[c];
    U[D[c]]=sz;
    U[sz]=c;
    D[c]=sz;
    if(H[r]<0)H[r]=L[sz]=R[sz]=sz;
    else
    {
        R[sz]=R[H[r]];
        L[R[H[r]]]=sz;
        L[sz]=H[r];
        R[H[r]]=sz;
    }
}
void place(int &p1,int &p2,int &p3,int &p4,int i,int j)
{
    p1=j,p2=n+i,p3=n+n+i-j+n,p4=n+n+n+n-1+i+j-1;
}
bool p[maxnode];
int a[55];
int main()
{
    int i,j,k,p1,p2,p3,p4;
    while(scanf("%d",&n)!=-1)
    {
        for(i=1; i<=n*6-2; ++i)p[i]=0;
        init(n*n,n*6-2);
        for(k=i=1; i<=n; ++i)
        {
            scanf("%d",&j);
            if(j)
            {
                place(p1,p2,p3,p4,i,j);
                p[p1]=p[p2]=p[p3]=p[p4]=1;
                Link((i - 1) * n + j,p1),Link((i - 1) * n + j,p2),Link((i - 1) * n + j,p3),Link((i - 1) * n + j,p4);
            }
        }
        for(i=1; i<=n; ++i)
            for(j=1; j<=n; ++j)
            {
                place(p1,p2,p3,p4,i,j);
                if(p[p1]||p[p2]||p[p3]||p[p4])continue;
                Link((i - 1) * n + j,p1),Link((i - 1) * n + j,p2),Link((i - 1) * n + j,p3),Link((i - 1) * n + j,p4);
            }
        Dance(0);
        for (int i = 0; i < ansd; i++)
        {
            int val = ans[i];
            int x = (--val) / n;
            int y = val % n;
            x++;
            y++;
            a[x] = y;
        }
        for (int i = 1; i <= n; i++)
        {
            if (i != 1) printf(" ");
            printf("%d", a[i]);
        }
        puts("");
    }
    return 0;
}


白書模板TLE:(???????)

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

const int maxnode = 55 * 55 * 4;
const int maxr = 55 * 55;
const int maxc = 55 * 6;
int N;

///精確區間覆蓋
///行編號從1開始,列編號爲1~c,結點0爲表頭結點
///注意給行和列的編號
///注意sz,ans.要自己初始化和賦值!!!
struct DLX
{
    int n , sz;                                                 // 每列的行數,節點總數
    int S[maxc];                                                // 各列節點總數
    int row[maxnode],col[maxnode];                              // 各節點行列編號
    int L[maxnode],R[maxnode],U[maxnode],D[maxnode];            // 十字鏈表

    int ansd, ans[maxr];                                         // 解,行數

    void init(int n )
    {
        this->n = n ;
        for(int i = 0 ; i <= n; i++ )
        {
            U[i] = i ;
            D[i] = i ;
            L[i] = i - 1;
            R[i] = i + 1;
        }
        R[n] = 0 ;
        L[0] = n;
        sz = n + 1 ;
        memset(S,0,sizeof(S));
    }
    void addRow(int r,vector<int> c1)
    {
        int first = sz;
        for(int i = 0 ; i < c1.size(); i++ )
        {
            int c = c1[i];
            L[sz] = sz - 1 ;
            R[sz] = sz + 1 ;
            D[sz] = c ;
            U[sz] = U[c];
            D[U[c]] = sz;
            U[c] = sz;
            row[sz] = r;
            col[sz] = c;
            S[c] ++ ;
            sz ++ ;
        }
        R[sz - 1] = first ;
        L[first] = sz - 1;
    }

    // 順着鏈表A,遍歷除s外的其他元素
#define FOR(i,A,s) for(int i = A[s]; i != s ; i = A[i])

    void remove(int c)
    {
        L[R[c]] = L[c];
        R[L[c]] = R[c];
        FOR(i,D,c)
        FOR(j,R,i)
        {
            U[D[j]] = U[j];
            D[U[j]] = D[j];
            --S[col[j]];
        }
    }
    void restore(int c)
    {
        FOR(i,U,c)
        FOR(j,L,i)
        {
            ++S[col[j]];
            U[D[j]] = j;
            D[U[j]] = j;
        }
        L[R[c]] = c;
        R[L[c]] = c;
    }
    bool dfs(int d)
    {
        if (d >= N)
        {
            ansd = d;
            return true;
        }
        if (!R[0]) return false;///!!!
        // 找S最小的列c
        int c = R[0], tmp = S[R[0]];
        FOR(i, R, 0)
        if (i <= N) if (S[i] < tmp) tmp = S[c = i];///斜線部分不遍歷
        else break;
        remove(c);
        FOR(i,D,c)
        {
            ans[d] = row[i];
            FOR(j,R,i) remove(col[j]);
            if(dfs(d + 1)) return true;
            FOR(j,L,i) restore(col[j]);
        }
        restore(c);

        return false;
    }
    bool solve(vector<int> & v)
    {
        v.clear();
        if(!dfs(0)) return false;
        for(int i = 0 ; i< ansd ; i ++ ) v.push_back(ans[i]);
        return true;
    }
};
DLX solver;
void decode(int val, int &x, int &y)
{
    val--;
    x = val / N;
    y = val % N;
    x++;
    y++;
}
vector<int>v;
bool p[55 * 55 * 4];
void place(int &p1,int &p2,int &p3,int &p4,int i,int j)
{
    p1=j,p2=N+i,p3=N+N+i-j+N,p4=N+N+N+N-1+i+j-1;
}
int main()
{
    int a[55];
    while (cin >> N)
    {
        memset(p, 0, sizeof(p));
        solver.init(6 * N - 2);
        for (int i = 1; i <= N; i++)
        {
            scanf("%d", &a[i]);
            if (!a[i]) continue;
            int p1, p2, p3, p4;
            place(p1, p2, p3, p4, i, a[i]);
            v.clear();
            v.push_back(p1);
            v.push_back(p2);
            v.push_back(p3);
            v.push_back(p4);
            p[p1] = p[p2] = p[p3] = p[p4] = 1;
            solver.addRow((i - 1) * N + a[i], v);
        }
        for (int i = 1; i <= N; i++)
        {
            for (int j = 1; j <= N; j++)
            {
                int p1, p2, p3, p4;
                place(p1, p2, p3, p4, i, j);
                if (p[p1] || p[p2] || p[p3] || p[p4]) continue;
                v.clear();
                v.push_back(p1);
                v.push_back(p2);
                v.push_back(p3);
                v.push_back(p4);
                solver.addRow((i - 1) * N + j, v);
            }
        }
        v.clear();
        solver.solve(v);
        for (int i = 0; i < v.size(); i++)
        {
            int x, y;
            decode(v[i], x, y);
            a[x] = y;
        }
        for (int i = 1; i <= N; i++)
        {
            if (i != 1) printf(" ");
            printf("%d", a[i]);
        }
        puts("");
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章