Spoj 1771

题意:

           跟n皇后一样,就是有些地方已经放了皇后,且范围是n  <= 50

          我的模板从 fp_hzq神牛哪里学到的

          他的博客: http://blog.csdn.net/fp_hzq/article/details/6797150

          从他的博客学到很多东西

          这道题与普通的精确覆盖不同,有些地方不用全部覆盖,只要覆盖行和列,对角线不用全部覆盖,

只要做一个约束条件,而我采用的判断是,当R[0] >2*n时就结束,意思是将行和列覆盖完就结束了,选取的列也是 <= 2 * n

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

#define N 55
#define ROW N * N
#define COLUMN N * 2 +  (2 * N - 1) * 2 + 10
#define AREA ROW * COLUMN

int U[AREA], D[AREA], L[AREA], R[AREA], C[AREA];
int int P[AREA], X[AREA], Y[AREA];
int H[ROW], S[COLUMN], Q[ROW];
int e;
void init(int n, int m){
    for(int i = 0; i <= n; i++) H[i] = -1;
    for(int i = 0; i <= m; i++){
        S[i] = 0;
        U[i] = D[i] = i;
        L[i+1] = i;
        R[i] = i + 1;
    }
    R[e = m] = 0;
}

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){
    for(int i = U[c]; i != c; i = U[i])
        for(int j  = L[i]; j != i; j = L[j])
            U[D[j]] = D[U[j]] = j, ++ S[C[j]];
    L[R[c]] = R[L[c]] = c;
}
int n;
int Dance(int k){
    if(R[0] > 2 * n){//(k >= n)
        for(int i = 0; i < k; i++){
            P[Y[Q[i]]] = X[Q[i]];
        }
        for(int i = 1; i <= n; i++) {
            printf("%d",P[i]);
            if(i != n) printf(" ");
        }
        printf("\n");
        return 1;
    }
    int c, tmp = ROW;
    for(int i = R[0]; i != 0; i = R[i])
        if(i <= 2 * n) {//(i <= n)
            if(tmp > S[i])
                tmp = S[c = i];
        } else {
            break;
        }
    remove(c);
    for(int i = D[c]; i != c; i = D[i]){
        Q[k] = i;
        for(int j = R[i]; j != i; j = R[j]) remove(C[j]);
        if(Dance(k + 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,int i, int j){
    C[++e] = c; ++S[c];
    Y[e] = i; X[e] = j;
    D[e] = D[c]; U[D[c]]  = e;
    U[e] = c;   D[c] = e;
    if(H[r] < 0) H[r] = L[e] = R[e] = e;
    else {
        R[e] = R[H[r]];
        L[R[H[r]]] = e;
        L[e] = H[r];
        R[H[r]] = e;
    }
}
int maze[N][N];
int c[4];
void find(int x, int y, int n){
    c[0] = x;  c[1] = n + y;
    c[2] = n * 2 + (x + y - 1);
    x = n - x + 1;
    c[3] = n * 2 + (2 * n - 1) + (x + y - 1);
}

int main(){
//    freopen("in","r",stdin);
    while(scanf("%d",&n) != -1){
        memset(maze,0,sizeof(maze));
        memset(ma,0,sizeof(ma));
        int x, y;
        x = n * n; y = 2 * n + (2 * n - 1) * 2;
        init(x,y);
        for(int i = 1; i <= n; i++){
            int tmp;
            scanf("%d",&tmp);
            if(tmp == 0) continue;
            maze[i][tmp] = 2;
            int s = i + tmp;
            for(int j = 1; j <= n; j++)
                if(maze[i][j] ==0) 
                    maze[i][j] = 1;
            for(int j = 1; j <= n; j++)
                if(maze[j][tmp] == 0)
                    maze[j][tmp] = 1;
            for(x = 1; x <= n; x++){
                y = s - x;
                if(y < 1 || y > n) continue;
                if(maze[x][y] == 0) maze[x][y] = 1;
            }
            s = tmp - i;
            for(x = 1; x <= n; x++){
                y = x + s;
                if(y < 1 || y > n) continue;
                if(maze[x][y] == 0) maze[x][y] = 1;
            }
        }
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                if(maze[i][j] != 1)
                {
                    find(i, j, n);
                    for(int k = 0; k < 4; k++)
                        Link((i-1) * n + j,c[k],i,j);
                }

        Dance(0);
    }
    return 0;
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值