[CF Gym 100827K] Towers [2014-2015 ACM-ICPC Pacific Northwest Regional Contest K]

题意

给定一个N*N可能不完整的数字矩阵需要填满,矩阵数字0->9,要求每一行每一列不能有重复数字。同时给出一些行和一些列的限制,要求从某个方向看某一行或一列“看到的”数字要与之相符。

题解

限制条件很强,要敢于暴力搜索。

代码

/****************************************\
* Author : ztx
* Title  : K - Towers
* ALG    : 搜索
* CMT    : 
* Time   :
\****************************************/

#include <cstdio>
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
typedef long long ll ;
typedef double lf ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
    ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
    if (CH == '-') NEG = true , CH = getchar() ;
    while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
    if (NEG) ret = -ret ;
}
template <typename TP>inline void readc(TP& ret) {
    while (ret=getchar() , ret<'!') ;
    //while (CH=getchar() , CH>'!') ;
}
template <typename TP>inline void reads(TP *ret) {
    ret[0]=0;while (CH=getchar() , CH<'!') ;
    while (ret[++ret[0]]=CH,CH=getchar(),CH>'!') ;
    ret[ret[0]+1]=0;
}

#include <cstring>

#define  maxn  7LL

const int dx[4] = {0,0,1,-1} ;
const int dy[4] = {1,-1,0,0} ;

#define  left  0
#define  right 1
#define  up    2
#define  down  3
#define  row   0
#define  col   1

int n , tott ;
int a[maxn][maxn] , px[maxn*maxn] , py[maxn*maxn] ;
bool exist[2][maxn][10] ;

inline bool check(int i,int j,int dir,int tot) {
    int look = 0 , now = 0 , exist = 0  ;
    if (dir == left) j = 1 ;
    if (dir == right) j = n ;
    if (dir == up) i = 1 ;
    if (dir == down) i = n ;
    for (;i>=1&&i<=n&&j>=1&&j<=n;i+=dx[dir],j+=dy[dir]) {
        if (a[i][j]) exist ++ ;
        if (a[i][j] > now) now = a[i][j] , look ++ ;
    }
    if (exist == n) return look == tot ;
    return true ;
}

inline bool use(int i,int j,int x) {
    if (exist[row][i][x]) return false ;
    if (exist[col][j][x]) return false ;
    a[i][j] = x ;
    if (a[i][0] && !check(i,j,left,a[i][0])) return a[i][j] = 0 ;
    if (a[i][n+1] && !check(i,j,right,a[i][n+1])) return a[i][j] = 0 ;
    if (a[0][j] && !check(i,j,up,a[0][j])) return a[i][j] = 0 ;
    if (a[n+1][j] && !check(i,j,down,a[n+1][j])) return a[i][j] = 0 ;
    exist[row][i][x] = exist[col][j][x] = true ;
    return true ;
}

#define  unuse(i,j,x) a[i][j] = exist[row][i][x] = exist[col][j][x] = 0 ;

bool dfs(int p) {
    if (p > tott) return true ;
    int x ;
    #define  i  px[p]
    #define  j  py[p]
    Rep (x,1,n) if (use(i,j,x)) {
        if (dfs(p+1)) return true ;
        unuse(i,j,x) ;
    }
    return false ;
    #undef i
    #undef j
}

int main() {
int T , ok , i , j ;
//    #define READ
    #ifdef  READ
        freopen(".in" ,"r",stdin ) ;
        freopen(".out","w",stdout) ;
    #endif
    for (read(T) ; T -- ; ) {
        tott = 0 ;
        memset(exist,0,sizeof exist) ;
        read(n) ;
        ok = true ;
        Rep (i,0,n+1) Rep (j,0,n+1) {
            #define  x a[i][j]
            readc(x) ;
            x = x == '-' ? 0 : x-'0' ;
            if (!ok || i<1 || i>n || j<1 || j>n) continue ;
            if (x) {
                if (exist[row][i][x]) ok = false ;
                if (exist[col][j][x]) ok = false ;
                exist[row][i][x] = exist[col][j][x] = true ;
            } else ++ tott , px[tott] = i , py[tott] = j ;
            #undef  x
        }
        if (ok)
            Rep (i,1,n) {
                if (a[i][0] && !check(i,i,left,a[i][0])) ok = false ;
                if (a[i][n+1] && !check(i,i,right,a[i][n+1])) ok = false ;
                if (a[0][i] && !check(i,i,up,a[0][i])) ok = false ;
                if (a[n+1][i] && !check(i,i,down,a[n+1][i])) ok = false ;
            }
        if (ok && dfs(1)) {
            Rep (i,1,n) {
                Rep (j,1,n) printf("%d",a[i][j]) ;
                puts("") ;
            }
        } else puts("no") ;
        puts("") ;
    }
    #ifdef  READ
        fclose(stdin) ; fclose(stdout) ;
    #else
        getchar() ; getchar() ;
    #endif
    return 0 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值