sgu224Little Queens 225. Little Knights

题意:

n*n(n<=10)的棋盘,求出放置m(m<=n*n)个皇后的方案数。

tip:

状态压缩+位运算 一行一行dfs
dfs(当前行号,列状态(哪个可以选可以不选),左上来的(哪个可以选可以不选),右上来的(哪个可以选可以不选),已放置棋子数)

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

int n,sum,bound,m;
void dfs(int step , int cal, int l, int r, int num) {
    int pos, p, i;
    if (step > n){
        if(num == m) sum++;
        return;
    }
    dfs(step + 1, cal, l>>1, r<<1, num);
    if (cal != bound){
        pos = (bound & (~ (cal|l|r)));
        while (pos != 0){
            p = pos & -pos;//last "one"
            pos = pos - p;
            dfs (step+1,cal|p,(l|p)>>1,(r|p)<<1,num+1);
        }
    }
}
int main() {
//  int p =8&-8;
//  cout <<p<<endl;
    scanf("%d%d",&n,&m);
    bound = (1<<n) - 1;
    dfs(1,0,0,0,0);
    printf("%d",sum);
}

题意:

放马

tip:

还是状压,位运算。。要打表

#include <cstdio>
#include <cstring>
#include <iostream>
#define LL long long
using namespace std;
LL  mark[110]={1,100,4662,135040,2732909,41199404,481719518,4491423916,34075586550,213628255072,1120204619108,4961681221524,18715619717199,60541371615660,168976761361446,409191804533576,864172675710439,1599730843649564,2609262108838924,3770687313420780,4857550050070531,5616928666465104,5874943705896600,5604501518609804,4917655076255841,3999855946779732,3034690618677388,2156485957257040,1437827591264317,899278231344296,526753407546620,288274613750624,146990556682887,69626509814580,30542906352994,12366448408056,4604442057431,1569983914256,487876545370,137395261280,34831261750,7884855000,1578162590,275861904,41455966,5246412,543534,44244,2652,104,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int state[30000];
int fstate[(1<<20)+1000];
int statenum =0 ;
LL f[2][29000][52];
int n,k;
int bitnum(int x){
    int sum =0;
    while(x){
      int  t = x&(-x);
      sum++;
      x -= t;
    }
    return sum;
}
void init_state(){
    statenum =0;
    int line1 ;
    int line2 ;
    for(int i = 0 ;i < (1<<(2*n) ) ;i++){
        line2 = i>>n;
        line1 = i- (line2 << n);
        if(line2&(line1<<2))    continue;
        if(line2&(line1>>2))    continue;
        statenum ++;
        state[statenum]= i;
        fstate[i] =statenum;
  }
}
int maxidx[20]={0,1,5,6,9,14,18,26,32,42,51};
void dfs(int r , int  i,int j, int  lev,int num){
      int line1 = ( j>>n );
      int line2 =  (line1<<n);
          line2 = j - line2;
      if(lev == n){
        for(int t = num;t <= maxidx[n];t++){
            int tmp = (line2<<n)+i;
            f[r%2][fstate[tmp]][t] += f[(r+1)%2][fstate[j]][t-num];
        }
        return ;
     }
     int st = (line1>>1)|(line1<<1)|(line2>>2)|(line2<<2);

     dfs(r,i,j,lev+1,num);
     if((st&(1<<lev)) == 0){
          dfs(r,i|(1<<lev),j,lev+1,num+1);
     }
}

void sov(){
    if(n == 10){
        cout << mark[k]<<endl;
        return ;
    }
    if(k > maxidx[n]){
        cout << 0 <<endl;;
        return ;
    }
    init_state();
    memset(f,0,sizeof(f));
    for(int  i = 1;i <= min(statenum,(1<<n)); i++){
        f[1][i][bitnum(state[i])]=1;
    }
    f[1][1][0]=1;
    for(int r=1;r<n;r++){
        memset(f[(r+1)%2],0,sizeof(f[(r+1)%2]));
        for(int j = 1;j <= statenum;j++){
            dfs(r+1,0,state[j],0,0);
        }
    }
    LL ans =  0;
    for(int i = 1;i <= statenum;i++){
        ans +=  f[n%2][i][k];
    }
    cout <<ans<<endl;;
}

int main(){
    cin >> n>>k;
    sov();
    return 0 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值