HDU - 1079 Calendar Game(博弈打表sg函数)

29 篇文章 4 订阅

题目链接:点击查看

题目大意:给出一个日期,两个人轮流按照规则操作,具体规则如下:

  1. 每次可以增加一天
  2. 每次可以增加一个月到下一个月的当天

首先到达2001年11月4日的人获胜,问谁能获胜

题目分析:因为是从1900年1月1日开始的,最多只跨越了100年,也就是100*365天,大概也就1e5的分支,我们可以直接用dfs进行sg打表,每一次至多有两个分支,可以用两个if套上好多个if else就好了。。这样的话时间复杂度我不太会算,但因为用了sg打表,也相当于是记忆化搜索了,避免了重复分支的多次调用,所以交上去之后15毫秒就过了,还要吐槽一点,我的笔记本太不给力了。。在本地T掉了,本来很失望的交上去却A掉了,emmm

最后再感谢zx学长的思路,直接上代码了:

#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream> 
using namespace std;

typedef long long LL;

const int inf=0x3f3f3f3f;

const int N=4e5+100;

int sg[2020][15][35];//sg函数,类似于记忆化搜索

const int mon[2][13]={{0,31,28,31,30,31,30,31,31,30,31,30,31},{0,31,29,31,30,31,30,31,31,30,31,30,31}};

bool is_year(int year)//判断是否为闰年
{
    if(year%4==0&&year%100!=0||year%400==0)
        return true;
    return false;
}

bool check(int a,int b,int c)//判断是否越界
{
    if(a>2001||a==2001&&b>11||a==2001&&b==11&&c>4)
        return false;
    return true;
}

bool dfs(int a,int b,int c)//记忆化搜索
{
    if(sg[a][b][c]!=-1)
        return sg[a][b][c];
    if(a==2001&&b==11&&c==4)
        return sg[a][b][c]=false;
    int pos=is_year(a);
    if(c<mon[pos][b]&&check(a,b,c+1))//下一天 
    {
        if(!dfs(a,b,c+1))
            return sg[a][b][c]=true;
    }
    else if(c==mon[pos][b]&&b!=12&&check(a,b+1,1))//跨月不跨年 
    {
        if(!dfs(a,b+1,1))
            return sg[a][b][c]=true;
    }
    else if(c==mon[pos][b]&&b==12&&check(a+1,1,1))//跨年
    {
        if(!dfs(a+1,1,1))
            return sg[a][b][c]=true;
    } 
    if(b<12)//下一个月的同一天
    {
        if(c<=mon[pos][b+1])//确保下一个月中有这一天 
            if(check(a,b+1,c))
                if(!dfs(a,b+1,c))
                    return sg[a][b][c]=true;
    }
    else if(b==12)//跨年
    {
        if(check(a+1,1,c))//12月和1月都是31天,所以不用特判 
            if(!dfs(a+1,1,c))
                return sg[a][b][c]=true;
    } 
    return sg[a][b][c]=false; 
}

int main()
{
//  freopen("input.txt","r",stdin);
    memset(sg,-1,sizeof(sg));
    int w;
    cin>>w;
    while(w--)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        if(dfs(a,b,c))
            printf("YES\n");
        else
            printf("NO\n");
    }
    

    
    
    
    
    
    
    
    
    
    

    return 0;
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Frozen_Guardian

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值