2024年睿抗机器人开发者大赛(RAICOM)省赛题解

第一题 模拟

我们直接按照题目模拟即可,使用%7来求解当前处于哪一天

int t,n,m;

void solve(){
    
    cin>>n>>m;
    int ans1 = 0,ans2 = 0;
    for(int i=1;i<=n;i++){
    	int x; cin>>x;
    	int day = (m+i-1)%7;
    	if(x>=35){
    		if(day!=4) ans1++;
    		else ans2++;
    	}
    }
    cout << ans1 << ' ' << ans2 << endl;
    return ;
}

第二题 模拟

按照意思模拟,对于排名加分可以写在数组里面这样就不用写很多if和else

int t,n,m;
int ans[30];
int g[]={0,12,9,7,5,4,3,3,2,2,2,1,1,1,1,1,0,0,0,0,0};
void solve(){
    
    n = 20;
    cin>>t;
    while(t--){
    	for(int i=1;i<=n;i++){
    		int r,c; cin>>r>>c;
    		ans[i] += g[r] + c;
    	}
    }
    for(int i=1;i<=n;i++) cout << i << ' ' << ans[i] << endl;
    return ;
}

第三题 bfs

题目告诉我们有一个位置的火炉被挡住了,那么最多也就是有几个小家伙(8个)是本来应该是很暖和但是现在却不是很暖和的,我们先按照题目给的小火炉可以求出所有暖和的,剩下的小伙子就是不暖和的,那么可能放置小火炉的位置就是这些不暖和小家伙周围的点,即是他们的九宫格,对这些可能是小火炉的点检查,当他是小火炉的时候是否满足所有小家伙都是温暖的,同时很冷的小家伙依旧很冷。

可以知道可能有小伙炉的位置也不会很多,如果很多说明一个炉子肯定不够,可以直接输出很冷,或者最后检查发现没有位置符合要求也是输出很冷

char s[M][M];
bool st[M][M];// 是不是暖和的
void solve(){
    
    cin>>n>>m;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			cin>>s[i][j];
	
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(s[i][j]=='m'){
				// 找到被暖和的位置
				for(int a=i-1;a<=i+1;a++)
					for(int b=j-1;b<=j+1;b++)
						if(s[a][b]=='w') st[a][b]=true;
			}
	
	vector<PII> v; // 没有被暖到的小伙子
	set<PII> S; // 可以是炉子的位置
	
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(s[i][j]=='w' and !st[i][j]){
				v.push_back({i,j});
				for(int a=i-1;a<=i+1;a++)
					for(int b=j-1;b<=j+1;b++)
						if(s[a][b]=='.') S.insert({a,b}); // 可以是小火炉的位置
			}
	
	if(v.size()>50 or S.size()>50){ // 数量过多明显无解
		cout << "Too cold!" << endl;
		return ;
	}
	
	vector<PII> ans;
	for(auto&[i,j]:S){ // 判断可以是小火炉的位置正不正确
		bool ok = true;
		set<PII> now;
		for(int a=i-1;a<=i+1;a++)
				for(int b=j-1;b<=j+1;b++)
						if(s[a][b]=='w' and !st[a][b]) now.insert({a,b}); // 被暖和了
						else if(s[a][b]=='c') ok = false;
		if(now.size()!=v.size()) ok = false;
		if(ok) ans.push_back({i,j});
	}
	if(ans.empty()){
		cout << "Too cold!" << endl;
		return ;
	}
	sort(ans.begin(),ans.end());
	for(auto&[a,b]:ans) cout << a << ' ' << b << endl;
    return ;
}

第四题 并查集

注意题目规定的章鱼子图的定义,可以得知要所在联通图的环只有一个的时候符合要求被称为章鱼子图,而有多个环或者没有环的时候就不是,维护环的的数量我们可以采用的方法有dfs,tarjan缩点、或者是用并查集来维护,一般而言并查集的写法是比较简单的优先考虑能不能用并查集来维护。

本题,我们可以通过并查集的方式维护每一个联通块中环的数量,(出现本来就在一个连通块的点对又有边就是出现了环)然后可以同时维护一个环时候的起点和终点可以考虑使用bfs维护环的长度

int t,n,m;
int p[N],sz[N],d[N];
vector<int> g[N];
int find(int x){
	if(x!=p[x]) p[x]=find(p[x]);
	return p[x];
}
void solve(){
    
    cin>>n>>m;
    for(int i=1;i<=n;i++) g[i].clear(),p[i]=i,d[i]=-1,sz[i]=0;
    
    // sz 表示出现了环的数量
    int ans=0,st,ed;
    while(m--){
    	int a,b; cin>>a>>b;
    	g[a].push_back(b);
    	g[b].push_back(a);
    	int fa = find(a),fb = find(b);
    	if(fa!=fb){ // 表示这写点还没有啥特殊关系
    		p[fa]=fb;
    		sz[fb] += sz[fa]; // a所在的连通块可能有环现在要和b连在一起要环的数量是会合并变多
    	}
    	else{ // 如果说这两个点本来就在一个连通块 那么这条边的出现就会是环的出现
    		sz[fa]++;
    		st = a, ed = b; // 这两个点肯定就是环上的点
    	}
    }
    
    // 只有一个环的才是 章鱼子图 题目定义 及是sz[i]==1
    
    // find(i) == i 表示和i在一个连通块的祖先信息 
    for(int i=1;i<=n;i++) if(find(i)==i and sz[i]==1) ans++;
    
    if(ans!=1){
    	cout << "No" << ' ' << ans << endl;
    	return ;
    }
    // st  和 ed 是环上的点 我只要不使用 st 和 ed 的边就可以用bfs找出环的数量
    queue<int> q;
    q.push(st);
    d[st] = 1;
    while(!q.empty()){
    	auto u = q.front(); q.pop();
    	for(auto&v:g[u]){
    		if(u==st and v==ed) continue;
    		if(d[v]==-1){
    			d[v]=d[u]+1;
    			q.push(v);
    		}
    	}
    }
    cout << "Yes" << ' ' << d[ed] << endl;
    return ;
}

第五题 排序+01背包

做题的时候可以先分析简单模型,比如本题,我们可以先考虑去掉一些东西,假设没有截止时间,那就是每个任务需要t时间,做完之后得到的贡献就是p,我们可以发现这就是01背包,不熟悉01背包的读者可以先自行去哔哩哔哩看视频或者博客了解,这里不做赘述。

但是,本题还有截止时间,我们可以注意到,应该优先考虑截止早的为什么呢,因为,这个任务的贡献必须在他截止之前才可以有答案,我们可以举一个简单的例子,如果是先算截止时间是3的任务,那么当你算截止时间是2的任务的时候,你就会发现3和2的信息没有办法结合起来,所以我们需要优先考虑截至时间早的,(也就是后效性)最后对所有节点求一遍最大值即可,为什么呢,因为并不是在最后节点的时候答案最大比如 2 2 100 和 3 3 1 ,最大贡献是2的时候的答案

struct code{
	int t,d,p;
	bool operator<(const code&t)const{
		return d<t.d;
	}
}e[N];
LL dp[N];

void solve(){
    
    memset(dp,0,sizeof dp);
    cin>>n;
    for(int i=1;i<=n;i++){
    	int t,d,p; cin>>t>>d>>p;
    	e[i]={t,d,p};
    }
    sort(e+1,e+1+n);
    
    for(int i=1;i<=n;i++){
    	auto [t,d,p]=e[i];
    	for(int j=d;j>=t;j--){
    		dp[j] = max(dp[j],dp[j-t]+p);
    	}
    	for(int i=1;i<N;i++) dp[i]=max(dp[i-1],dp[i]);
    }
    cout << dp[N-1] << endl;
    return ;
}

上述代码并非最后提交通过代码,而是作者赛后重写了一遍,赛时题目按照上述实现均已通过,如有问题请联系作者更正

评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值