HDU 1565 状态压缩

题意:

你一个n*n的格子的棋盘,每个格子里面有一个非负数。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。(n <= 20)

算法:

因为n比较少20,可以用状态压缩,1表示方格该数取,0表示不取。

每一行的状态有1<<N种,先预处理所有合法状态,即相邻两位不能为1,

判断条件是i && (i<<1),下一行的状态要满足条件的是跟上一行没有相

邻的 num[i] & num[j] == 0

int num[21000]; //状态
int sum[21][21000]; //该状态的和
int len;
int mt[30][30]; //存储方格

View Code
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int num[21000]; //状态 
int sum[21][21000]; //该状态的和 
int len;
int mt[30][30];  //存储方格 
int N;
int dp[30][21000];

void pre(int N)
{ 
  len = 0;
  for( int i = 0; i < (1<<N); i++)
  {
     if( i & (i<<1) )
         continue;
     num[len] = i;
     for( int k = 1; k <= N; k++)
     {
      int ans = i;
      for( int j = N; j > 0; j--)
      {
        if( ans&1 )
        {
         sum[k][len] += mt[k][j];
        }
        ans = ans>>1;  
      }
     }
     len++;
   }          
}

int main( )
{
  while( scanf("%d",&N) != EOF)
  {
    memset(sum, 0, sizeof(sum));
    for( int i = 1; i <= N; i++)
         for( int j = 1; j <= N; j++)
            scanf("%d",&mt[i][j]);      
    pre( N );
    memset(dp, 0, sizeof(dp));
    dp[0][0] = 0;
    for( int n = 1; n <= N; n++)
     for( int i = 0; i < len; i++)
      for( int j = 0; j < len; j++)
      {
             if(  (num[i]&num[j]) == 0 )
             {
                if( dp[n][i] < dp[n-1][j] + sum[n][i] )
                {
                    dp[n][i] = dp[n-1][j] + sum[n][i];    
                }     
                  
             }     
                
      }
    int ans = 0;
    for( int i = 0; i < len; i++)
       if( dp[N][i] > ans )
           ans = dp[N][i];
    printf("%d\n", ans);
  }    
  return 0;  
}

posted on 2012-08-05 09:13  more think, more gains  阅读(191)  评论(0编辑  收藏  举报

导航