• BZOJ 1087 题解【状压DP】


    1087: [SCOI2005]互不侵犯King

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 3112  Solved: 1816
    [Submit][Status][Discuss]

    Description

      在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
    左下右上右下八个方向上附近的各一个格子,共8个格子。

    Input

      只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

    Output

      方案数。

    Sample Input

    3 2

    Sample Output

    16

    HINT

     

    Solution

    这是一道状压DP题,本蒟蒻第一次做状压,坑了好久。

    我们用0和1代表棋盘上的某点是否放棋子,每一行的状态都可以用唯一的一个十进制数表示,我们可以通过位运算,得到合法状态数,并统计即可。

    DP方程:

    f[ i + 1 ][ p + num[ y ] ][ y ] += f[ i ][ p ][ x ] 

      1 /**************************************************************
      2     Problem: 1087
      3     User: shadowland
      4     Language: C++
      5     Result: Accepted
      6     Time:40 ms
      7     Memory:6336 kb
      8 ****************************************************************/
      9  
     10 #include "bits/stdc++.h"
     11  
     12 using namespace std ;
     13 const int maxNum = 512 ;
     14 const int maxN = 10 ;
     15  
     16 bool feasible[ maxNum << 2 ] , feasible_flat[ maxNum << 1 ][ maxNum << 1 ] ;
     17 long long f[ maxN ][ 100 ][ maxNum ] , num[ maxNum << 2 ] ;
     18  
     19 long long Ans ; 
     20  
     21 inline bool Check ( const int x , const int y ) {
     22         if ( ( ( x & y ) == 0) && ( ( x & ( y >> 1 ) ) == 0 ) && ( ( x & ( y << 1 ) ) == 0 ) ) return true ;
     23         else return false ;
     24 }
     25  
     26 void Init ( const int N , const int M ) {
     27         int _cnt = 0 ;
     28         for ( int i=0 ; i<=( 1 << N ) - 1 ; ++i ) {
     29                 if ( ( i & ( i << 1 ) ) == 0 ) {//状态合法记录 
     30                         _cnt = 0 ;
     31                         for ( int Base = i ; Base ; Base >>= 1 ) _cnt += ( Base & 1 ) ;
     32                         num[ i ] = _cnt ;// 
     33                         feasible[ i ] = true ; 
     34                 }
     35         }
     36         for ( int i=0 ; i<=( 1 << N ) - 1 ; ++i ) {
     37                 if ( feasible[ i ] ) {
     38                         for ( int j=0 ; j<=( 1 << N ) - 1 ; ++j ) {
     39                                 if ( feasible[ j ] ) {
     40                                         if ( Check ( i , j ) ) {
     41                                                 feasible_flat[ i ][ j ] = true ;
     42                                         }
     43                                 } 
     44                         }
     45                 }
     46         }
     47 } 
     48  
     49 void DEBUG_( int n , int m ) {
     50         printf ( "
    " ) ;
     51         for ( int i=0 ; i<=( 1 << n ) - 1 ; ++i ) 
     52                 printf ( "%d " , feasible[ i ] ) ;
     53     
     54         printf ( "
    " ) ;
     55         for ( int i=0 ; i<=( 1 << n ) -1 ; ++i ) {
     56                 for ( int j=0 ; j<=( 1 << n ) - 1 ; ++j ) {
     57                         printf ( "%d " , feasible_flat[ i ][ j ] ) ;
     58                 }
     59                 printf ( "
    " ) ;
     60         }
     61 }
     62  
     63 void DEBUG___( int n , int m ) {
     64         for ( int i=1 ; i<=n ; ++i ) {
     65                 for ( int j=0 ; j<=( 1 << n ) - 1 ; ++j ) {
     66                         for ( int k=0 ; k<= ( 1 << n ) - 1 ; ++k ) {
     67                                 printf ( "%d ",f[i][j][k]);
     68                         }
     69                 }
     70         }
     71 }
     72 int main ( ) {
     73         int N , M ;
     74         scanf ( "%d %d" , &N , &M ) ;
     75         Init( N , M ) ; 
     76         for ( int i=0 ; i<=( 1 << N ) - 1 ; ++i ) {//第一行的所有合法状态 
     77                 if ( feasible[ i ] ) {
     78                         f[ 1 ][ num[ i ] ][ i ] = 1 ;
     79                 }
     80         }
     81         for ( int j = 1 ; j<N ; ++j ) {
     82                 for ( int x = 0 ; x<= ( 1 << N ) - 1 ; ++x ) {
     83                         if ( feasible[ x ] ) {//x状态合法 
     84                                 for ( int y=0 ; y<= ( 1 << N ) - 1 ; ++y ) {
     85                                         if ( feasible[ y ] ) {//y状态合法 
     86                                                 if ( feasible_flat[ x ][ y ] ) {
     87                                                         for ( int p=num[ x ] ; p + num[ y ] <=M ; ++p ) {
     88                                                                 f[ j + 1 ][ p + num[ y ] ][ y ] += f[ j ][ p ][ x ] ;
     89                                                         }
     90                                                 }
     91                                         }
     92                                 }
     93                         }
     94                 }
     95         }
     96         //DEBUG_( N , M ) ;
     97         //DEBUG___( N , M ) ;
     98         for ( int i=0 ; i<= ( 1 << N ) - 1 ; ++i ) {
     99                 Ans += f[ N ][ M ][ i ] ;//统计最终合法状态 
    100         }
    101         cout << Ans << endl ;
    102         return 0 ;
    103 }
    View Code

    一定要开long long 。不开long long 见祖宗,十年OI一场空

    2016-10-12 23:20:05

    (完)

  • 相关阅读:
    谷歌翻译python接口
    SRILM的安装方法
    语言模型srilm基本用法
    SRILM语言模型格式解读
    矩阵理解
    python生成器 协程
    python Queue模块使用
    scrapy 学习笔记2
    scrapy 学习笔记1
    xpath语法规则
  • 原文地址:https://www.cnblogs.com/shadowland/p/5954517.html
Copyright © 2020-2023  润新知