dfs与博弈论——日历游戏

***星星***

之前做过不少博弈论的题目(石子问题等等),如果题目规定两者都用最优解答,那么我们可以分析 我进行什么操作能让对方面临相同的必输态。然后一步步分析即可。但有时我们没法人为判断出必输态和必胜态,因为情况态度太复杂,或者我们只能判断出很简单的状态的输赢。这时候我们就要递推解决问题了。那么一般用dfs进行递推。

下面来看这道题目——日历游戏


日历游戏

时间限制: 1.000 Sec  内存限制: 128 MB
提交 状态

题目描述

moreD和moreD的宠物CD正在玩一个日历游戏,开始时,他们从1900年1月1日到2012年12月22日(你懂的……)选一个日期开始,依次按照如下规则之一向后跳日期:
1.跳到日历上的下一天。
2.跳到日历上的下个月的同一天(如果不存在,则不能这么做)。
要是谁正好到达2012年12月22日那么他就赢了,如果到达这天之后的日期那他就输了——原因你也懂的。
每次都是moreD先走的。
现在,给你一个日期,请问moreD一定能赢吗?

输入

输入共T行,每行三个整数,Y、M、D,分别表示年、月、日。日期在1900年1月1日到2012年12月22日之间(包含两端)。
T并不在输入数据当中。

输出

要是moreD一定能赢,输出一行YES,否则输出NO

样例输入 Copy
【样例1】
2012 12 20
【样例2】
2012 12 21
样例输出 Copy
【样例1】
NO
【样例2】
YES
提示

对于50%的数据,是1949年1月1日后的日期。 T <= 5
对于100%的数据,是1900年1月1日后的日期。T <= 


思路:这道题虽说是博弈题,但感觉没有太大的逻辑和输赢态的转移,简单来说就是每一步有两种操作,我们无法轻易判断出那种操作容易赢。

那么,我们就用dfs递推来实现,反正一步两种操作,一个不行就走另一个呗~(这有点像折半搜索,都是两种可能枚举)。

当然如果一步步纯枚举不记录会T。那么就要记录状态,我们把年月日储存在map中,这样以后如果重复直接return即可,不用再来一遍重复操作。

这题还有就是next_day last_day next_year last_year的操作比较亮点,要注意使用简介的写法。先写day++,然后再判断分情况,就很简单,而不是写一大堆...

看代码:

#include<iostream>
#include<map>
using namespace std;
int this_month(int y,int i,int d){
    if(i==1||i==3||i==5||i==7||i==8||i==10||i==12){
        return 31;
    }
    if(i==4||i==6||i==9||i==11){
        return 30;
    }
    return 28+((y%4==0&&y%100!=0)||y%400==0);
}
void next_day(int &y,int &m,int &d){
    d++;
    if(d>this_month(y,m,d)){
        d=1;m++;
    }
    if(m>12){
        m=1;y++;
    }
}
void last_day(int &y,int &m,int &d){
    d--;
    if(d==0)
        m--,d=this_month(y,m,d);
    if(m<1)
        y--,m=12,d=this_month(y,m,d);
}
void next_month(int &y,int &m,int &d){
    m++;
    if (m > 12)
        m = 1, y++;
}
void last_month(int &y,int &m,int &d){
    m--;
    if (m < 0)
        m = 12, y--;
}
bool check(int y,int m,int d){
    if(m<12){
        if(d<=this_month(y,m+1,d)){
            return true;
        }
    }else{
        if(d<=31){
            return true;
        }
    }
    return false;
}
map<int,int>ds;
int dfs(int y,int m,int d){
    if(y>2012){
        return 1;
    }
    if(y==2012&&m==12&&d==22){
        return -1;
    }else if(y==2012&&m==12&&d>22){
        return 1;
    }
    if(ds[y*10000+m*100+d]){
        return ds[y*10000+m*100+d];
    }
    int ans;
    next_day(y,m,d);
    ans=-dfs(y,m,d);
    last_day(y,m,d);
    if(ans==-1&&check(y,m,d)){
        next_month(y,m,d);
        ans=-dfs(y,m,d);
        last_month(y,m,d);
    }
    ds[y*10000+m*100+d]=ans;
    return ans;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    int a,b,c;
    while (cin>>a>>b>>c)
    {
        if (dfs(a, b, c) > 0)
        {
            cout<<"YES\n";
        }
        else
        {
            cout<<"NO\n";
        }
    }
}

还有,if如果不加大括号里面的语句要用“,”而不是“;”。。。错好几次了都。。。

  • 13
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DFS算法是一种用于图遍历或树遍历的算法。其核心思想是从起点开始递归地深入每一个可能的分支,直到无法继续为止,然后回溯到上一个节点,继续尝试其他分支。 DFS算法有两种实现方式:递归实现和非递归实现(使用栈)。 递归实现的DFS算法伪代码: ``` DFS(node): if node is None: return visit(node) for child in node.children: DFS(child) ``` 非递归实现的DFS算法伪代码: ``` DFS(node): stack = [node] while stack: node = stack.pop() if node.visited: continue visit(node) node.visited = True for child in node.children: stack.append(child) ``` 其中,visit(node)表示对节点node进行操作,例如打印节点值、记录路径等。 DFS算法的时间复杂度为O(V+E),其中V为节点数,E为边数。因为每个节点和每条边都只会被访问一次。 下面是一个例题,用DFS算法求解从起点到终点的路径(leetcode 79题): 给定一个二维网格和一个单词,找出该单词是否存在于网格中。 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。 示例: ``` board = [ ['A','B','C','E'], ['S','F','C','S'], ['A','D','E','E'] ] 给定 word = "ABCCED", 返回 true. 给定 word = "SEE", 返回 true. 给定 word = "ABCB", 返回 false. ``` 实现代码: ```python class Solution: def exist(self, board: List[List[str]], word: str) -> bool: if not board or not board[0]: return False m, n = len(board), len(board[0]) visited = [[False] * n for _ in range(m)] directions = [(0, 1), (0, -1), (1, 0), (-1, 0)] def dfs(i, j, k): if k == len(word): return True if i < 0 or i >= m or j < 0 or j >= n or visited[i][j] or board[i][j] != word[k]: return False visited[i][j] = True for dx, dy in directions: if dfs(i+dx, j+dy, k+1): return True visited[i][j] = False return False for i in range(m): for j in range(n): if dfs(i, j, 0): return True return False ``` 时间复杂度为O(m*n*3^k),其中m、n为网格大小,k为单词长度。因为每个格子都有可能走,所以是O(m*n),而每次调用dfs函数会向四个方向递归,每个方向都不能重复走,所以是3^k。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值