UVALive 5760 Alice and Bob(博弈+记忆化dp or 找规律)

题意:

黑板上写了n(n<=50)个不超过1000的数,
双方轮流进行以下操作中的一种:

  • 将一个数减1,当某个数为0时将其擦去;
  • 将两个数擦去,并将两个数之和写上黑板;

擦去最后一个数为胜者,Alice先手,求最后胜者。

思路:

如果所有数都是大于1的数,共可执行 cnt 次操作,其中:

cnt=sum(a[i])+n1

当 cnt 为奇数时先手胜利,偶数时后手胜利。
如果有的数为1,把1与其他数合并,操作数-1;把1直接-1,操作数-2.于是我们可以根据这个转移规则来进行dp。
dp[i][j] = 1的个数为i,其他>1的数可操作次数为j时的胜负情况。

当然了,找规律也可以。

代码:

//记忆化dp
#include<bits/stdc++.h>
using namespace std;

int n ;
const string win[2] = { "Bob", "Alice" } ;
int dp[55][50005] ;
bool dfs( int n , int m )
{
    if ( dp[n][m] != -1 ) return dp[n][m] ;
    int &res = dp[n][m] = 0 ;
    if ( !n ) return res = ( m & 1 );
    if ( !m ) return res = ( n % 3 != 0 ) ;
    if ( n == 1 ) return res = 1 ;
    if ( m == 1 ) return res = dfs( n + 1 , 0 ) ;
    if ( !dfs( n - 1 , m ) ) res = 1 ;
    if ( m > 1 && !dfs( n - 1 , m + 1 ) ) res = 1 ;
    if ( m > 1 && !dfs( n , m - 1 ) ) res = 1 ;
    if ( n > 1 && !dfs( n - 2 , m? m + 3 : m + 2 ) ) res = 1 ;
    return res ;
}
int main()
{
    int t ; cin >> t ; int kase = 1 ;
    memset( dp , -1 , sizeof dp ) ;
    while ( t-- ) {
        scanf( "%d" , &n ) ;
        int one = 0 , more = 0 ;
        for ( int i = 0 ; i < n ; i++ ) {
            int tmp ; scanf( "%d" ,&tmp ) ;
            if ( tmp == 1 ) one++ ;
            else more += tmp ;
        }
        if ( one != n ) more += n - one - 1 ;
        bool ok = dfs( one , more ) ;
        printf( "Case #%d: " , kase++ ) ;
        cout << win[ok] << endl ;
    }
    return 0;
}
//找规律
#include<bits/stdc++.h>
using namespace std;

const string win[2] = { "Bob", "Alice" } ;
int n ;
bool check( int cnt , int sum )
{
    if ( sum == cnt || sum == cnt + 2 ) {
        if ( cnt % 3 == 0 ) return 0 ;
        else ;
    } else {
        sum += ( n - 1 ) ;
        if ( sum % 2 == 0 && cnt % 2 == 0 ) return 0 ;
    }
    return 1 ;
}
int main()
{
    int t ; cin >> t ; int kase = 1 ;
    while ( t-- ) {
        scanf( "%d" , &n ) ;
        int one = 0 , sum = 0 ;
        for ( int i = 0 ; i < n ; i++ ) {
            int tmp ; scanf( "%d" ,&tmp ) ;
            if ( tmp == 1 ) one++ ;
            sum += tmp ;
        }
        bool ok = check( one , sum ) ;
        printf( "Case #%d: " , kase++ ) ;
        cout << win[ok] << endl ;
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值