您的位置:首页 > 大数据 > 人工智能

HDU_4317 Unfair Nim 状态压缩dp

2012-07-31 19:58 477 查看
http://acm.hdu.edu.cn/showproblem.php?pid=4317

题意:

有N堆石子,每堆石子都有一定数目的石子,现在你可以往石堆中加任意多的石子,使得先手必败。

思路:

首先我们可以可以发现的一点就是,根据Nim博弈的知识,我们知道N堆石子先手必败的条件是N堆石子的石子数异或值为0,那么问题就转变成了在N堆石子中加一定数量的石子,使得最后异或值变成0。因为异或是一个按照每位来进行的运算,因此我们考虑逐位来进行,对于N个数的某一位,它的值取决于前一个(i-1)对其的进位和本身加上的值,因此我们在满足第i位的时候,需要考虑的一个因素是i-1的进位,我们用一个状态j来表示进行情况,这样第i位的最终结果应该是本身的值然后加上进位过来的值,在加上额外加上的值就是最终的值了。到这里我们就可以想到状态压缩dp了,用F(i,j)
表示前i位都已经变成了0 ,并且第i位向第i+1位进位的状态为j的最少需要加的石子数。状态转移当然是由i-1来,那么就还需要枚举第i-1为向第i位的进位k,然后运用位运算进行求解。

具体的实现过程是这样的:

已经产生的进位情况为:tmp = num[i] & k

第i进位之后的值为 : y = num[i] ^ k ;

判断已经产生的进位是否合法: j & tmp == tmp ?

还需要多少位的进位: x = j ^ tmp

进位需要的代价:t[ x & y ] * d[i] + t[ x^y&x ] * 2 * d[i] ;

进位完全之后的新状态为 : now = y & (~x )

代码:

#include <stdio.h>
#include <string.h>
const int BB = 21 ;
int N ;
int t[1<<BB] ;
int d[BB+1] ;
int num[BB] ;
int val[BB] ;
int maxbit ;
int dp[BB][1<<10] ;

void init(){
d[1] = 1 ;
for(int i=2;i<=BB;i++)   d[i] = d[i-1]<<1 ;
for(int i=0;i<(1<<BB);i++){
int tmp = i ;   t[i] = 0 ;
while( tmp )   {
if( tmp&1 ) t[i] ++ ;
tmp >>= 1 ;
}
}
}

int MIN(int a, int b){
if(a == -1) return b ;
else        return a < b ? a : b ;
}
void solve(){
memset(dp,  -1, sizeof(dp));
dp[0][0] = 0 ;
int MM = 1 << N ;
for(int i=1;i<=maxbit;i++){
for(int j=0;j<MM;j++){
if( dp[i-1][j] == -1 )  continue ;
int tmp = num[i] & j ;
int v = num[i] ^ j;
for(int k=tmp;k<MM;k++){
if( (k&tmp) == tmp ) {
int x = k ^ tmp ;
int add = t[x & v]*d[i] + t[ (x^v)&x ] * 2 * d[i] ;
int now = v & (~x) ;
if( (t[now]&1)==0 ){
dp[i][k] = MIN(dp[i][k] , dp[i-1][j] + add );
}
else if( t[now] != N ){
dp[i][k] = MIN( dp[i][k] , dp[i-1][j] + add + d[i] );
}
}
}
}
}
int ans = -1 ;
for(int j=0;j<MM;j++){
if( dp[maxbit][j]==-1 || t[j]%2==1)   continue ;
ans = MIN( ans ,dp[maxbit][j] ) ;
}
if(ans == -1)   printf("impossible\n");
else        printf("%d\n",ans);
}

int main(){
init() ;
while( scanf("%d",&N) == 1){
maxbit = 0 ;
for(int i=1;i<=N;i++){
scanf("%d",&val[i]);
int tmp = val[i] ;
int c = 0 ;
while( tmp ){
c ++ ;
tmp >>=1 ;
}
if( maxbit < c )    maxbit = c ;
}
for(int i=1;i<=maxbit;i++){
num[i] = 0 ;
for(int j=1;j<=N;j++){
if( val[j]&d[i] ) num[i] += d[j] ;
}
}
solve() ;
}
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: