Why so serious? --[NKU]schindlerlee

2010年1月12日星期二.sgu223 状态压缩动态规划

2010年1月12日星期二.sgu223
 状态压缩动态规划

sgu223:n*n的棋盘上放置k个王的放置方法。
基本方法和pku1185中的递推方法是一样的。
都是先求出一行中的所有合法状态,然后进行按行递推,
在递推的过程中判断两行之间是否有冲突。

#define L(n) (n << 1)
#define R(n) (n >> 1)
#define bin(n) (1 << n)
#define low(n) (n & (-n))
//http://www.cppblog.com/schindlerlee/
const int N = 10;
int n,sum,full;
int s[bin(N)],c[bin(N)],top;

LL f[N
+3][bin(N)][N*N];
//行 最后一行状态 已用的王的个数

bool judgeRow(int t)
{
  
int stat = t,cnt = 0;
  
int tp = 0,b = 0;
  
while(t > 0) {
      
if(b & t) {
          
return false;
      }
      b 
= t & 1,t >>= 1;
      
if(b == 1) cnt ++;
  }
  
if(sum < cnt)
    
return false;

  s[top] 
= stat,c[top] = cnt,top++;
  
return true;
}

bool contradict(int up,int down)
return ((up & down) || (L(up) & down) || (R(up) & down)); }

int main()
{
  
int i,j,k;
  scanf(
"%d%d",&n,&sum);
  full 
= bin(n) - 1;
  memset(f,
0,sizeof(f));
  
for(i = 0;i <= full;i++) {
      judgeRow(i);
  }

  f[
0][0][0= 1;
  
for(i = 1;i <= n;i++) {
      
for(j = 0;j < top;j++) {
          
int s1 = s[j],c1 = c[j]; //current

          
for(k = 0;k < top;k++) {
              
for(int c2 = 0;c2 <= sum;c2++) {
                  
int s2 = s[k];
                  
if(!f[i-1][s2][c2] ||c1 + c2 > sum) continue;
                  
//状态不可达或者使用王的数量超过k
    
                  
if(!contradict(s1,s2)) { //状态不冲突
                      f[i][s1][c1+c2] += f[i-1][s2][c2];
                  }
              }
          }
      }
  }
  LL res 
= 0;
  
for(i = 0;i <= full;i++) {
      res 
+= f[n][i][sum];
  }
  cout 
<< res << endl;

  
return 0;
}


 

posted on 2010-01-13 22:39 schindlerlee 阅读(1103) 评论(0)  编辑 收藏 引用 所属分类: 解题报告


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理