CSP 2017-12

1.最小差值
排序枚举

int a[N];

int main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    cin>>a[i];

    sort(a,a+n);

    int ans=0x3f3f3f3f;
    for(int i=1;i<n;i++)
    ans=min(ans,a[i]-a[i-1]);
    cout<<ans;
}

2.游戏
约瑟夫环

bool is(int m,int k){
	return m%k==0||m%10==k;
}

int main(){
	vector<int> v;
	int n,k;
	cin>>n>>k;
	
	for(int i=1;i<=n;i++)
	v.push_back(i);
	
	int m=1;//当前报的数
	int p=0;//数组下标 
	while(v.size()!=1){
		if(is(m,k)){
			v.erase(v.begin()+p);
			p--;
		}
		m++;
		p++;
		p%=v.size();
	}
	cout<<v[0];
}

y总的代码: 用队列确实要快不少

bool is(int x,int k){
	return x%k==0||x%10==k;
}
int main(){
	int n,k;
	cin>>n>>k;
	
	queue<int> q;
	for(int i=1;i<=n;i++)
		q.push(i);

	int j=1; //j记录当前时间 
	while(q.size()>1){
		int t=q.front();
		q.pop();
		
		if(!is(j++,k)) q.push(t);
	}
	
	cout<<q.front();
}

3.Crontab
注意到n最大是20,所以每次可以枚举时间,然后再枚举每个Crontab,看看是否符和要求即可
具体实现:

  1. 实现一个date类,每次对该date类加一分钟
  2. 实现一个Crontab类,用字符串来构造Crontab,实现给一个date,Crontab可以判断是否是自己的合法时间
  3. 枚举所有date即可

但是模拟过程太复杂了试着敲敲吧
y总的日期时间模拟题模板:

int months[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
	
	bool is_leap(){
		return year%400==0||(year%4==0&&year%100!=0);
	}
	
	int get_month(){
		if(month==2) return months[2]+is_leap();
		return months[month];
	}
	
	void next(){
		if(++mintues>=60){
			mintues=0;
			if(++hours>=24){
				hours=0;
				week=(++week)%7;
				if(++day>get_month()){
					day=1;
					if(++month>=13){
						month=1;
						year++;
					}
				}
			}
		}
	}
main(){
// t为被枚举的时间,e为终止时间,s为题目给定的起始时间
	while(t<e){
		if(!(t<s)){
		/*
		函数体
		*/
		}
		t.next();
	}
}

题目的坑梳理一下:

  1. 时间从1970年开始的,而不是1900年
  2. 二月是28天,而不是30天(这其实是我自己的问题,在这里卡了很久)
#include<iostream>
#include<sstream>
#include<set>
#include<vector>
#include<algorithm>
using namespace std;
#define N 1010
int months[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
struct date{

	bool is_leap(){
		return year%400==0||(year%4==0&&year%100!=0);
	}
	
	int get_month(){
		if(month==2) return months[2]+is_leap();
		return months[month];
	}
	
	int year,month,day,hours,mintues,week; 
	date(const string &s){
		sscanf(s.c_str(),"%04d%02d%02d%02d%02d",&year,&month,&day,&hours,&mintues);
	}
	
	bool operator<(const date& dt) const{
	if(year!=dt.year) return year<dt.year;
	if(month!=dt.month) return month<dt.month;
	if(day!=dt.day) return day<dt.day;
	if(hours!=dt.hours) return hours<dt.hours;
	return mintues<dt.mintues;
	}	
	
	void next(){
		if(++mintues>=60){
			mintues=0;
			if(++hours>=24){
				hours=0;
				week=(++week)%7;
				if(++day>get_month()){
					day=1;
					if(++month>=13){
						month=1;
						year++;
					}
				}
			}
		}
	}
	
	void out(){
		printf("%04d%02d%02d%02d%02d",year,month,day,hours,mintues);
	}
};
string mon_str[13]={"","jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"};
string week_str[7]={"sun","mon","tue","wed","thu","fri","sat"};
void lower(string &s){
	for(int i=0;i<s.length();i++){
		if(s[i]>='A'&&s[i]<='Z') s[i]+='a'-'A';
	}
}

struct Crontab{
	set<int> mintues,hours,day,month,week;
	string command;
	int to_int(const string &s){
		int ans=0;
		for(int i=0;i<s.length();i++)
		ans=ans*10+s[i]-'0';
		return ans;
	}
	int fnd(string s){
	lower(s);
	for(int i=0;i<13;i++)
	if(s==mon_str[i]) return i;
	for(int i=0;i<7;i++)
	if(s==week_str[i]) return i;
	return to_int(s);
	}
	void solve(const string &s,set<int> &st,int start,int end){
		if(s=="*")
		{
		for(int i=start;i<=end;i++)
		st.insert(i);
		}
		else
		for(int i=0;i<s.length();){
			int j=i;
			while(j<s.length()&&(s[j]>='0'&&s[j]<='9'||s[j]>='a'&&s[j]<='z'||s[j]>='A'&&s[j]<='Z')) j++;
			if(j>=s.length()) {
				st.insert(fnd(s.substr(i,j-i)));
				i=j;
			}else if(s[j]==','){
				st.insert(fnd(s.substr(i,j-i)));
				j++;
				i=j;
			}else { 
				int k=j+1;
				while(k<s.length()&&(s[k]>='0'&&s[k]<='9'||s[k]>='a'&&s[k]<='z'||s[k]>='A'&&s[k]<='Z')) k++;
				int l=fnd(s.substr(i,j-i));
				int r=fnd(s.substr(j+1,k-j-1));
				for(int p=l;p<=r;p++)
				st.insert(p);
				i=k+1;
			}
		}
	}

	Crontab(const string &s){
		stringstream ss(s);
		string temp;
		
		ss>>temp;
		solve(temp,mintues,0,59);
		
		ss>>temp;
		solve(temp,hours,0,23);
		
		ss>>temp;
		solve(temp,day,1,31);
		
		ss>>temp;
		solve(temp,month,1,12);
		
		ss>>temp;
		solve(temp,week,0,6);
		
		ss>>temp;
		command=temp;
	}

	bool in(date &dt){
		return mintues.find(dt.mintues)!=mintues.end()&&hours.find(dt.hours)!=hours.end()&&day.find(dt.day)!=day.end()&&month.find(dt.month)!=month.end()&&week.find(dt.week)!=week.end();
	}
};

vector<Crontab> vec;
int main(){
	int n;
	string start,end;
	cin>>n>>start>>end;
	date s(start),e(end);
	getchar();
	for(int i=0;i<n;i++){
		string temp;
		getline(cin,temp);
		vec.push_back(Crontab(temp));
	}
	date t("197001010000"); //1970年1月1日0时0点 星期四 
	t.week=4; 
	while(t<e){
		if(!(t<s)){
		for(int i=0;i<vec.size();i++){
				if(vec[i].in(t)){
					t.out();
					cout<<" "<<vec[i].command<<endl;
				}
			}
		}
		t.next();
	}
}

4.行车路线:
因为题目中有:
保证答案不超过10的6次方
所以小路长度绝对不超过1000
可以设一个数组dis[n][1010]
dis[i][j]记为遍历到i点时上一条小路长度为j时的疲劳值
用优先队列去更新即可
但是要注意:
bfs一般有两种模板,第一种是将判断条件放在q.pop之后的,这种模板比较好写,但是容易超时
第二种就是下边这种模板,比较难想也不好敲,因此可以先敲模板1,超时了再换成模板2即可

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
#define INF 0x3f3f3f3f
#define N 510
struct node{
	int to,val;
	int t;//最后一条小路的长度 或 路的类型 
	bool operator<(const node &n)const{
	return val>n.val;
	}
};
vector<node> G[N];
int dis[N][1010];
bool vis[N][1010];
// dis[i][j]记为到达点i且最后一条小路长度为j的疲劳值 
void dijistra(){
	memset(dis,INF,sizeof(dis));
	memset(vis,0,sizeof(vis));
	priority_queue<node> q;
	q.push((node){1,0,0});
	while(q.size()){
		
		node f=q.top();
		q.pop();
	
		for(int i=0;i<G[f.to].size();i++){
			node &nxt=G[f.to][i];
			if(nxt.t){//小道 
				int len=(nxt.val+f.t);
				int newdis=f.val-f.t*f.t+len*len;
				if(len<=1000&&dis[nxt.to][len]>newdis&&newdis<=1000000){
				q.push((node){nxt.to,newdis,nxt.val+f.t});	
				dis[nxt.to][len]=newdis;
				}
			}else{
				int newdis=f.val+nxt.val;
				if(dis[nxt.to][0]>newdis&&newdis<=1000000){
				q.push((node){nxt.to,newdis,0});	
				dis[nxt.to][0]=newdis;
				}
				
			}
		}
	}
}
int main(){
	int n,m;
	cin>>n>>m;
	while(m--){
		int t,a,b,c;
		cin>>t>>a>>b>>c;
		G[a].push_back((node){b,c,t});
		G[b].push_back((node){a,c,t});
	}
	
	dijistra();
	int ans=INF;
	for(int i=0;i<1010;i++){
		ans=min(ans,dis[n][i]);
	}
	
	cout<<ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值