HDOJ 2167 Pebbles

这种类型的题目似乎很常见——方格棋盘,搜索某种状态。你也许会大喊:“嘿,伙计,为什么不再来一份?……”

但是我就他喵的又敲了2个钟头,其中莫名其妙的错误就和绵羊身上的毛一样多。

在这之前我要承认这是一道很繁琐的题目。第一题目没有给出棋盘的长宽,需要处理字符串;第二当你敲下第200行代码之后再简单的题也会突然变得复杂起来。

单纯的搜索是不可能的。N*N= 225,这样的数据规模已经注定了纯搜的失败。接着考虑分行。

上一行的情况直接决定了下一行。这就够了。当然,不是像某些题目一样,第一行决定之后,你就可以泡一杯咖啡,坐着等待AC了。但是当第一行决定之后,第二行的情况始终是有限种并且可记录。为什么不在开始时预处理下这些变换呢?这样就节省下无数时间。

考虑到每一格只有两种情况:取或者不取。N<15,第一选择就是位操作。

现在设状态为F(i,j),表示第i行下取到j时的最大值。每一种状态都是唯一确定且满足最优子结构。故DP得最终解。

 

#include  < iostream >
#include 
< string >
using   namespace  std;

#define  setMax(x,y) ( x = x > y ? x : y )

int  N, a[ 16 ][ 16 ], b[ 16 ][ 40000 ];
int  c[ 16 ][ 40000 ];
int  p[ 16 ];
string  str;
int  ans  =   0 ;

typedef 
struct
{
    
int u, v;
}
 Num;
Num trans[
50000 ];
int  len;

int  checkOne (  int  n )
{
    
int i;
    
for ( i = 0; i < 14; i ++ )
    
{
        
if ( n & p[i] && n & p[i + 1] )
            
return 0;
    }

    
return 1;
}


void  init ()
{
    str 
+= ' ';
    
string sub;
    
int i, j = 0;
    
while ( str.size () )
    
{
        i 
= str.find_first_of ( ' ' );
        sub 
= str.substr ( 0, i );
        
int sum = 0;
        str 
= str.substr ( i + 1, str.size () );
        
for ( i = 0; i < sub.size (); i ++ )
            sum 
= sum * 10 + sub[i] - '0';
        a[N][j 
++= sum;
    }

    N 
++;
}


int  checkPebbles (  int  r,  int  n )
{
    
int i, sum;
    
for ( i = 0, sum = 0; i < N; i ++ )
    
{
        
if ( n & p[i] )
            sum 
+= a[r][i];
    }

    
return sum;
}


void  dp ()
{
    
int i, j;
    memset ( b, 
0xffsizeof ( b ) );
    
for ( i = 0; i < N; i ++ )
    
{
        
for ( j = 0; j < ( 1 << N ); j ++ )
        
{
            c[i][j] 
= checkPebbles ( i, j );
        }

    }

    ans 
= 0;
    
int u, v;
    
for ( j = 0; j < len; j ++ )
    
{
        u 
= trans[j].u, v = trans[j].v;
        
if ( u == 0 && v < ( 1 << N ) )
        
{
            
//printf ( "%d %d ", u, v );
            b[0][trans[j].v] = c[0][trans[j].v];
            setMax ( ans, b[
0][trans[j].v] );
        }

    }

    
//printf ( "%d ", ans );
    for ( i = 1; i < N; i ++ )
    
{
        
for ( j = 0; j < len; j ++ )
        
{
            u 
= trans[j].u, v = trans[j].v;
            
if ( u >= ( 1 << N ) || v >= ( 1 << N ) )
                
continue;
            
if ( b[i - 1][u] == -1 )
                
continue;
            
//printf ( "%d %d %d %d %d %d ", i, u, v, b[i][v], b[i - 1][u], c[i][v] );
            setMax ( b[i][v], b[i - 1][u] + c[i][v] );
            setMax ( ans, b[i][v] );
        }

        
//printf ( "#%d ", ans );
    }

    printf ( 
"%d ", ans );
}


void  proc ()
{
    dp ();    
    
//printf ( "%d ", len );
    N = 0;
    memset ( b, 
0x00sizeof ( b ) );
}


void  dfs (  int  i,  int  n,  int  m )
{
    
if ( i == 15 )
    
{
        trans[len].u 
= n, trans[len ++].v = m;
        
return;
    }

    
//printf ( "%d %d %d ", i, n, m );
    int li = i - 1, hi = i + 1;
    
if ( li >= 0 && n & p[li] || li >= 0 && m & p[li] || hi < 15 && n & p[hi] || n & p[i] )
        dfs ( i 
+ 1, n, m );
    
else
    
{
        dfs ( i 
+ 1, n, m );
        dfs ( i 
+ 1, n, m | p[i] );
    }

}


void  checkAdj ()
{
    len 
= 0;
    
int i, j;
    
for ( i = 0, j = 1; i < 15; i ++, j *= 2 )
        p[i] 
= j;
    
for ( i = 0; i < ( 1 << 15 ); i ++ )
    
{
        
if ( checkOne ( i ) )
            dfs ( 
0, i, 0 );
    }

    printf ( 
"%d ", len );
}


int  main ()
{
    
//freopen ( "in.txt", "r", stdin );
    
//freopen ( "out.txt", "w", stdout );
    memset ( a, 0x00sizeof ( a ) );
    checkAdj ();
    
//pt ();
    N = 0;
    
while ( getline ( cin, str ) )
    
{
        
string t = str;
        
if ( t == "" )
            proc ();
        
else
            init ();
    }

    
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值