sgu225 装压DP&位运算

本文介绍了一种使用动态规划和深度优先搜索解决骑士放置问题的方法。通过对棋盘状态的合理编码,利用预处理合法状态的方式减少了计算量,最终实现了高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意是:给出一个 n*n 的棋盘 ,问放置 k 的 骑士 相当于 象棋中的马  有多少中放置方法。。。

n等于10 是TLE ,于是 n=10 打表

用 dfs写的 ,运行时间长,但代码简单。。 

开数组时 用到滚动数组。。。 

由于攻击范围是 两行 ,所以 是在三行之间做DP ,每种状态表示两行 ,这样上下三行之间的关系就两种状态直接的关系。。

相当于  f[ i ] [ j ] = opt(f[ j ][ t ]);

此题由于两行之间会攻击, 所以两行状态 合成一中状态时 (就是用最长二十位 的数来表示两行状态,10 位 表示 一行),合法的状态数 就会减少。。 可以预处理出所有合法状态。。。。

#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 i ){
int sum =0;
	while(i!=0){
	  int  t = i&(-i);
	  sum++;
	  i-=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 = line2 << n;
      line1 = i - line1;
      if(line2&(line1<<2)){
        continue;
      }
      if(line2&(line1>>2)){
        continue;
      }
      statenum ++;
      state[statenum]= i;
      fstate[i] =statenum;
  }
}
int maxidx []={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))){ 
          dfs(r,i|(1<<lev),j,lev+1,num+1);
     }
}



void  solve (){
	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<=statenum;i++){
	   if(i>(1<<n)){
	      break;
	   }
	   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;
	solve();
  return 0 ;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值