0613挑战赛总结(旷野)

过程

考试时就绞尽脑汁去想,但最后可能知识没学扎实,也可能运气原因,最后只考了个第五,考试结束后回头一看,倒数第二题瞬间就通透了,欲哭无泪。考试前还是要把心态调整好,考试尽力而为,不留遗憾就行。

失误

在思考倒数第二题时本来有思路,做了一次,一直输出零就慌了,然后心态没调过来,索性第五题全员骗分,要不然排名还要跌几番。所以在错了时,不要慌,徐徐渐进。

易错点

第三题纯纯广搜诱捕器,模版一套就完事,但一交,Memory Limit Exceeded (36)。我一开始就蒙了,写了代码调试了一下才发现重复次数太多了,这里就需要一个memo数组记录重复,减少循环次数
但加在哪里就需要深思,每一次是对马可以跳的地方搜索,所以应该在最深一层循环判断,其余直接写就行

    queue<node>q;
	q.push(node(xp,yp,0));
	int dx[]={-1,-2,-2,-1,1,2,2,1},dy[]={2,1,-1,-2,2,1,-1,-2};
	while(!q.empty()){
		node now=q.front();
		q.pop();
		for(int i=0;i<8;i++){
			node p(now.x+dx[i],now.y+dy[i],now.s+1);
			if(p.x>=0&&p.x<n&&p.y>=0&&p.y<n){
				if(memo[p.x][p.y]) continue;
		    	memo[p.x][p.y]=true;
				if(p.x==x2&&p.y==y2) return p.s;
				else q.push(p);
			}
		}
	}
	return -1;

题解

最后一题有亿点点难,老师讲后写个题解理一理。
曲线谜题
首先这么多线不可能全部都起作用,所以一定有一个规律筛选掉一些线段,那么通过画几次图可知,只有两点都在图边缘上的线才有阻拦性作用,其余都可以绕过去。所以输入先判断,筛选掉一些。
但剩下的怎么判断交叉呢?我们要转化一下,二维的计算我们肯定不行(神犇当我没说),所以要转化成线段,这时,我们将四条边拆开,再把每一条线段做以数字标记,将两个点按一定顺序排序,每一条线就变成一维上的线段了,但怎么排序呢?先参悟一下图,再看结果请添加图片描述

拆成一维后:请添加图片描述
在图中就可以清楚地看出有两个交叉点,因为是把四条边依次拆开所以以编号分类,再分析排法

bool cmp(node a,node b){
	if(a.id==1&&b.id==1) return a.y>b.y;
	if(a.id==2&&b.id==2) return a.x<b.x;
	if(a.id==3&&b.id==3) return a.y<b.y;
	if(a.id==4&&b.id==4) return a.x>b.x;
	return a.id<b.id;
}

然后因为是判断不是算,就可以像括号序列一样用栈来判断,每一个点如果栈空,入栈,如果与栈顶数字编号相同,代表与其他线不交叉,出栈,其余则入栈,最后判断栈空就行

s.push(a[0].col);
	for(int i=1;i<cnt;i++){
		if(s.empty()){
			s.push(a[i].col);
			continue;
		}
		if(a[i].col==s.top()){
			s.pop();
			continue;
		}
		s.push(a[i].col);
	}
	if(s.empty()) printf("YES");
	else printf("NO");

整体情况就是这样,其余就是细节处理,为了方便检查,用函数封装筛选和拆开操作的子操作更好

bool check(int x,int y){return x==0||x==r||y==0||y==c;}//点是否在边上
int f(int x,int y){
	if(x==0) return 1;
	if(x==r) return 3;
	if(y==0) return 2;
	if(y==c) return 4;
} //点在那一条边

最后所有步骤汇合起来就组成了超长代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
struct node{
	int x,y,id,col;
}a[N];
int r,c,n,cnt;
bool cmp(node a,node b){
	if(a.id==1&&b.id==1) return a.y>b.y;
	if(a.id==2&&b.id==2) return a.x<b.x;
	if(a.id==3&&b.id==3) return a.y<b.y;
	if(a.id==4&&b.id==4) return a.x>b.x;
	return a.id<b.id;
}
bool check(int x,int y){return x==0||x==r||y==0||y==c;}
int f(int x,int y){
	if(x==0) return 1;
	if(x==r) return 3;
	if(y==0) return 2;
	if(y==c) return 4;
} 
stack<int>s;
int main(){
	scanf("%d%d%d",&r,&c,&n);
	for(int i=1;i<=n;i++){
		int xi1,yi1,xi2,yi2;
		scanf("%d%d%d%d",&xi1,&yi1,&xi2,&yi2);
		if(check(xi1,yi1)&&check(xi2,yi2)){
			a[cnt].x=xi1,a[cnt].y=yi1,a[cnt].col=i;
			a[cnt].id=f(xi1,yi1);
			cnt++;
			a[cnt].x=xi2,a[cnt].y=yi2,a[cnt].col=i;
			a[cnt].id=f(xi2,yi2);
			cnt++;
	    }
	}
	sort(a,a+cnt,cmp);
	s.push(a[0].col);
	for(int i=1;i<cnt;i++){
		if(s.empty()){
			s.push(a[i].col);
			continue;
		}
		if(a[i].col==s.top()){
			s.pop();
			continue;
		}
		s.push(a[i].col);
	}
	if(s.empty()) printf("YES");
	else printf("NO");
}

本人蒟蒻,写得不好,请见谅

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值