Crontab题解csp

文章讲述了如何使用C++编程语言解决一个涉及配置合法性的编程问题,通过暴力遍历和桶排序优化算法,检查时间区间内的配置是否满足特定条件。作者分享了代码片段和关键步骤,包括处理英文缩写、计算月份天数、判断闰年以及处理星期等复杂逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.解题思路

暴力,从开始时间s循环到结束时间e,以每分钟增加,遍历所有配置,看其值是否合法,合法输出相应的命令,求星期可以参考之前csp的节日,从1970年1月1日推导,或者用蔡勒公式直接算,对于配置的各项允许的值,首先判断是否等于‘*’,等于则将len长度的v数组全部置为一,表示0~len-1的值都是合法的,若不等于则以逗号为分隔符将字符串分割,再查找是否有-,没有直接将字符串转为对应数字或者月份或者星期,否则以-为参考将字符串一分为二,算出两端的值l,r将区间[l,r]的值全部置为一。

ps:这题debug到怀疑人生,需要注意输入的月份和星期不一定是标准输入(即开头大写后续小写),还有就是暴力带来的超时问题,一开始是用数组保存每个配置允许的值,只能拿80分,后来采用桶排序思想,空间换时间,加快很多。

2.满分代码

#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;

//处理英文缩写
map<string,int> dic={{"jan",1},{"feb",2},{"mar",3},{"apr",4},{"may",5},{"jun",6},
                      {"jul",7},{"aug",8},{"sep",9},{"oct",10},{"nov",11},{"dec",12},
                      {"sun",0},{"mon",1},{"tue",2},{"wed",3},{"thu",4},{"fri",5},{"sat",6}};
//平年的每月天数
int mon[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int get(string s)
{
	if(isdigit(s[0]))return stoi(s);
	transform(s.begin(),s.end(),s.begin(),::tolower);
	return dic[s];
}
int isleap(int y)
{
	return ((y%400==0)||((y%4==0)&&(y%100!=0)))?1:0;
}
int weekday(int year,int month,int day)
{
	int sum=0;
	for(int i=1970;i<year;i++)
	{
		if(isleap(i))sum+=366;
		else sum+=365;
	}
	for(int i=1;i<month;i++)
	{
		if(i==2&&isleap(year))sum+=29;
		else sum+=mon[i];
	}
	sum+=day-1;
	return (sum%7+4)%7;
}
vector<int> workstr(string str,int len)
{
	vector<int>v(len);
	if(str=="*")//len区间内都可以 1表示可以 0表示不可以 
	{
		for(int i=0;i<len;i++)
		{
			v[i]=1;
		}
	}
	else{
		vector<string>val;
		int p=str.find(",");
		while(p!=-1)
		{
			val.push_back(str.substr(0,p));
			str=str.substr(p+1);
			p=str.find(",");
		}
		val.push_back(str);
		for(auto s:val)//"-"
		{
			
			int p=s.find("-");
			if(p==-1)v[get(s)]=1;
			else
			{
				int l=get(s.substr(0,p));
				int r=get(s.substr(p+1));
				for(int i=l;i<=r;i++)
				{
					v[i]=1;
				}
			}
		}
	} 
	return v;
}
struct CMD
{
    vector<int>v[5];
    string cmd;
    CMD(){
	}
	CMD(string s0,string s1,string s2,string s3,string s4,string c)
	{
		v[0]=workstr(s0,60);//minute
		v[1]=workstr(s1,24);//hour
		v[2]=workstr(s2,32);//day of month
		v[3]=workstr(s3,13);//month
		v[4]=workstr(s4,7);//day of week
		cmd=c;
	}
}C[26];
struct time{
	int y,m,d,h,mi,w;
	void add()
	{
		mi++;
		if(mi==60)
		{
			mi=0;
			h++;
			if(h==24)
			{
				h=0;
				d++;
				w=(w+1)%7;
				int tmp;
				if((m==2)&&isleap(y))tmp=29;
				else tmp=mon[m];
				if(d>tmp)
				{
					d=1;
					m++;
					if(m==13)
					{
						m=1;
						y++;
					}
				}
			}
		}
	}
	bool operator<(const time &t)const{
		if(y!=t.y)return y<t.y;
		if(m!=t.m)return m<t.m;
		if(d!=t.d)return d<t.d;
		if(h!=t.h)return h<t.h;
		return mi<t.mi;
	}
};
int main()
{
	int n;
	time s,e;
	scanf("%d %04d%02d%02d%02d%02d %04d%02d%02d%02d%02d",&n,&s.y,&s.m,&s.d,&s.h,&s.mi,&e.y,&e.m,&e.d,&e.h,&e.mi);
	s.w=weekday(s.y,s.m,s.d);//开始时间是星期几 
	e.w=weekday(e.y,e.m,e.d);//结束时间是星期几
	for(int i=0;i<n;i++)
	{
		string s0,s1,s2,s3,s4,c;
		cin>>s0>>s1>>s2>>s3>>s4>>c;
		C[i]=CMD(s0,s1,s2,s3,s4,c);//每条配置信息 
	} 
	for(auto i=s;i<e;i.add())//从起始时间到结束时间按每分钟间隔增长 
	{
		for(int j=0;j<n;j++)//n条配置信息
		{
			if(C[j].v[0][i.mi]&&C[j].v[1][i.h]&&C[j].v[2][i.d]&&C[j].v[3][i.m]&&C[j].v[4][i.w])
			{
				printf("%04d%02d%02d%02d%02d ",i.y,i.m,i.d,i.h,i.mi);
				cout<<C[j].cmd<<endl;
			}
		} 
	} 
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值