信息学奥赛一本通 1974:【16NOIP普及组】回文日期 | 洛谷 P2010 [NOIP2016 普及组] 回文日期

【题目链接】

ybt 1974:【16NOIP普及组】回文日期
洛谷 P2010 [NOIP2016 普及组] 回文日期

【题目考点】

1. 模拟

【解题思路】

解法1:枚举 日期结构体

设表示日期的结构体,属性包括年月日,方法有:进入下一天,以及判断当前日期是否是回文的。
输入是日期是字符串,构造函数中将该字符串前4个字符变为数值,即为年。中间两个字符变为月,最后两个字符变为日。年月日是整型变量,此处可以使用substr()函数取子串,以及stoi()函数将字符串转为整数。
设让当前日期变为下一天的函数next(),先让日加1,如果日超过本月天数,那么月份加1,日变为1。如果月份超过12,那么年份加1,月份变为1。如果月份变化,更新本月天数md。
判断当前日期是否是回文的,可以将年月日进行数字拆分,每一位保存在长为8的整型数组中。遍历数组的一半(<n/2),判断这个数组前后对应位置是否相同。如果相同,那么这个日期就是回文的。
主函数中,让d为起始日期,每次循环判断当前日期是否是回文的,如果是则计数,而后让日期变为下一天。如果当前日期是终止日期,那么跳出循环。
最后输出计数。
复杂度为两个日期数值的差值,极端情况下,从0年1月1日到9999年12月12日,一共有约 366 ∗ 10000 = 3 ∗ 1 0 6 366*10000=3*10^6 36610000=3106天,是可以接受的。

解法2:深搜 构造回文串

用整型数组保存数字,深搜构造所有可能的回文数字。构造出回文数字后,判断该日期是否合法,以及该日期是否在起始与终止日期之间。
最差情况下,只需要搜索4位数字,每位数字有10种,最大搜索次数为 1 0 4 10^4 104次,优于解法1。

【题解代码】

解法1:枚举 日期结构体

#include<bits/stdc++.h>
using namespace std;
struct Date//日期结构体
{
    
    
    int y, m, d, md;//y:年, m:月, d:日, md:当前月份天数
    Date(string s)//以字符串初始化日期
    {
    
    
        y = stoi(s.substr(0, 4));
        m = stoi(s.substr(4, 2));
        d = stoi(s.substr(6));
        md = getMonthDay();
    }
    bool isLeap()//判断当年是否是闰年
    {
    
    
        return y % 400 == 0 || y % 100 != 0 && y % 4 == 0;
    }
    int getMonthDay()//获取当前月份的天数 
    {
    
    
        if(m == 2)
            return isLeap() ? 29 : 28;
        else if(m == 4 || m == 6 || m == 9 || m == 11)
            return 30;
        else
            return 31;
    }
    void next()//日期变为下一天 
    {
    
    
        d++;
        if(d > md)//如果日超出当月总天数
        {
    
    
            d = 1;//日设为1
            m++;//月份加1
            if(m > 12)//如果月份超出12
            {
    
    
                y++;
                m = 1;
            }
            md = getMonthDay();
        }
    }
    bool isHuiwen()//s:将当前日期转为字符串
    {
    
    
        int a[10] = {
    
    y/1000, y/100%10, y/10%10, y%10, m/10, m%10, d/10, d%10};
        for(int i = 0; i < 4; ++i)
            if(a[i] != a[7-i])
                return false;
        return true;
    }
    bool isSame(Date b)
    {
    
    
        return y == b.y && m == b.m && d == b.d;
    }
};
int main()
{
    
    
    string s1, s2;
    int ct = 0;//ct:计数
    cin >> s1 >> s2;//s1:起始日期字符串 s2:终止日期字符串 
    Date d(s1), d2(s2);
    while(true)
    {
    
    
        if(d.isHuiwen())
            ct++;
        if(d.isSame(d2))
            break;
        d.next();
    }
    cout << ct << endl;
    return 0;
}

解法2:深搜 构造回文串

#include<bits/stdc++.h>
using namespace std;
#define N 8
int d[N], d1[N], d2[N], ct;
bool isLater(int a[], int b[])//日期b是否与日期a相同,或在日期b的时间后面 
{
    
    
    int y_a = a[0]*1000+a[1]*100+a[2]*10+a[3], m_a = a[4]*10+a[5], d_a = a[6]*10+a[7]; 
    int y_b = b[0]*1000+b[1]*100+b[2]*10+b[3], m_b = b[4]*10+b[5], d_b = b[6]*10+b[7];
    if(y_b < y_a)
        return false;
    else if(y_b > y_a)
        return true;
    else
    {
    
    
        if(m_b < m_a)
            return false;
        else if(m_b > m_a)
            return true;
        else
            return d_b >= d_a;
    }
}
bool isValidDate(int a[])//日期a是否是合法的 
{
    
    
    int md[13] = {
    
    0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int year = a[0]*1000+a[1]*100+a[2]*10+a[3], month = a[4]*10+a[5], day = a[6]*10+a[7]; 
    if(month > 12 || month < 1)
        return false;
    if(year % 400 == 0 || year % 100 != 0 && year % 4 == 0)//根据是否是闰年改变2月天数 
        md[2] = 29;
    else
        md[2] = 28;
    if(day > md[month] || day < 1)//如果日子超过当月的天数,则不合法 
        return false;
    return true;
} 
void dfs(int k)//将d[k]与d[7-k]赋值 
{
    
    
    if(k == 2)
    {
    
    //d[0],d[1]与d[6],d[7]都赋值完成,看看d[6]d[7]是不是合法日期 
        int day = d[6]*10+d[7];
        if(day > 31 || day < 1)//日期最大为31 
            return;
    }
    if(k == 4)//如果完成所有位置的赋值 
    {
    
       
        if(isValidDate(d) && isLater(d1, d) && isLater(d, d2))//d是合法日期,且在d1~d2之间 
            ct++;//计数
        return; 
    }
    for(int i = 0; i <= 9; ++i)
    {
    
    
        d[k] = d[7-k] = i;//前后对应位置都为i 
        dfs(k+1);//看下一对位置 
    }
}
void toNum(int a[], string s)
{
    
    
    for(int i = 0; i < s.length(); ++i)
        a[i] = s[i] - '0';
}
int main()
{
    
    
    string s1, s2;
    cin >> s1 >> s2;//s1:起始日期字符串 s2:终止日期字符串 
    toNum(d1, s1);
    toNum(d2, s2);
    dfs(0); 
    cout << ct << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lq1990717/article/details/125923947