糯米

TI DaVinci, gstreamer, ffmpeg
随笔 - 167, 文章 - 0, 评论 - 47, 引用 - 0
数据加载中……

POJ 1143 Number Game 动态规划+位操作

题目大意:
两个人玩游戏。轮流取数字,范围在1~20之间。
规定:
1. 取过的数字不能再取。
2. 取过的数字的倍数不能再取。
3. 任意个(2)的和不能再取。

当某个人发现没有数字可取时,他就输了。
给出一个“残局”。问,我现在应该怎么取,才能保证胜利。

思路:
其实这个也不是很难的博弈问题。只是搜索就可以解决了。要用位来表示当前剩余数字的状态,
方便保存动态规划的结果。


#include <stdio.h>

#define N 20

char dp[2][1 << (N + 1)];

__inline 
int use(int visited, int idx)
{
    
int i;

    
for (i = 0; i + idx <= N; i++{
        
if (visited & (1 << i))
            visited 
|= 1 << (i + idx);
    }

    
return visited;
}


int dfs(int my_step, int visited)
{
    
int i, r;

    
if (visited == (1 << (N + 1)) - 1
        
return !my_step;
    
    r 
= dp[my_step][visited];
    
if (r)
        
return r - 1;

    
for (i = 2; i <= N; i++{
        
if (visited & (1 << i))
            
continue;
        r 
= dfs(!my_step, use(visited, i));
        
if (my_step && r)
            
return 1;
        
if (!my_step && !r)
            
return 0;
    }


    dp[my_step][visited] 
= !my_step + 1;
    
return !my_step;
}


int main()
{
    
int n, v, i, arr[24], cnt, t;

    freopen(
"e:\\test\\in.txt""r", stdin);

    
for (t = 1; scanf("%d"&n), n; t++{
        v 
= ((1 << (N + 1)) - 1& ~2;
        
while (n--{
            scanf(
"%d"&i);
            v 
&= ~(1 << i);
        }

        cnt 
= 0;
        
for (i = 2; i <= N; i++{
            
if (v & (1 << i))
                
continue;
            
if (dfs(0, use(v, i)))
                arr[cnt
++= i;
        }

        printf(
"Test Case #%d\n", t);
        
if (cnt) {
            printf(
"The winning moves are:");
            
for (i = 0; i < cnt; i++
                printf(
" %d", arr[i]);
            printf(
"\n");
        }
 else 
            printf(
"There's no winning move.\n");
        printf(
"\n");
    }


    
return 0;
}


posted on 2010-02-27 16:55 糯米 阅读(1121) 评论(0)  编辑 收藏 引用 所属分类: POJ


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