acwing----春季每日一题2022篇(三)

水桶传递队列(bfs + 技巧)

题目链接

方法一 : BFS

解题思路
这题由于是从一个点对另一个点的最短距离。因此利用BFS每一次都只拓展一层的特性,当我们第一层搜索到终点的时候的距离就是最短距离。

  • 湖和牛棚哪个当起点和终点都是一样的。

代码:

#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
#define x first
#define y second
typedef pair<int, int>PII;
PII s, e;
const int N = 12;
int n = 10, f[N][N];
char g[N][N];

int dx[4] = {0, 0, 1, -1}, dy[4] = {1, -1, 0, 0};

int bfs() {
	queue<PII>q;
	q.push(s);
	while (q.size()) {
		auto u = q.front();
		q.pop();
		for (int i = 0 ; i < 4 ; ++i) {
			int xx = u.x + dx[i], yy = u.y + dy[i];
			if (xx && xx <= n && yy && yy <= n && g[xx][yy] != 'R' && !f[xx][yy] ) {
				f[xx][yy] = f[u.x][u.y] + 1;
				if (xx == e.x && yy == e.y)
					return f[xx][yy];
				q.push({xx, yy});
			}
		}
	}
	return f[e.x][e.y];
}

int main() {
	for (int i = 1 ; i <= n ; ++i)
		cin >> (g[i] + 1);
	for (int i = 1 ; i <= n ; ++i)
		for (int j = 1; j <= n; ++j)
			if (g[i][j] == 'B')
				s = {i, j};
			else if (g[i][j] == 'L')
				e = {i, j};
	cout << bfs() - 1 << endl;
	return 0;
}

方法二 : 技巧 + 数学知识

解题思路
我们先不看岩石的作用的话,该题下两个点的最短距离应该是两个坐标之间的曼哈顿距离 - 1,
首先,如果湖和牛棚不在同一行也不再同列,那么不管岩石在哪里我们都能取到理论最小值。如图
在这里插入图片描述

那么什么时候岩石会影响到这个呢?答案就是当 湖和牛棚在同一行或者同一列的时候,且这个时候岩石出现在两者的连线之间,那么我们就需要多出两头牛来绕路了。

代码:
在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
char s[11];
int sx,sy,ex,ey,rx,ry;
int main()
{
    for(int i=1;i<=10;i++){
        cin>>s+1;
        for(int j=1;j<=10;j++){
            if(s[j]=='R')rx=i,ry=j;
            else if(s[j]=='B')ex=i,ey=j;
            else if(s[j]=='L')sx=i,sy=j;
        }
    }
    int ans=abs(sx-ex)+abs(sy-ey)-1;
    if((rx==sx&&sx==ex&&!(sy<ry^ry<ey))||(ry==sy&&sy==ey&&!(sx<rx^rx<ex)))ans+=2;
    cout<<ans;
}

阻挡广告牌I (计算几何 ,矩形面积)

题目链接

解题思路:
本题难点是如何快速求出,两个矩形至今相交的面积出来。如下图

在这里插入图片描述
两个矩形的水平边投影到 x 轴上的线段分别为 [ ax 1 , ax 2 ] [\textit{ax}_1, \textit{ax}_2] [ax1,ax2] [ bx 1 , bx 2 ] [\textit{bx}_1, \textit{bx}_2] [bx1,bx2]竖直边投影到 y 轴上的线段分别为 [ ay 1 , ay 2 ] [\textit{ay}_1, \textit{ay}_2] [ay1,ay2] [ by 1 , by 2 ] [\textit{by}_1, \textit{by}_2] [by1,by2]。如果两个矩形重叠,则重叠部分的水平边投影到 x 轴上的线段为 [ max ⁡ ( ax 1 , bx 1 ) , min ⁡ ( ax 2 , bx 2 ) ] [\max(\textit{ax}_1, \textit{bx}_1), \min(\textit{ax}_2, \textit{bx}_2)] [max(ax1,bx1),min(ax2,bx2)],竖直边投影到 y 轴上的线段为 [ max ⁡ ( ay 1 , by 1 ) , min ⁡ ( ay 2 , by 2 ) ] [\max(\textit{ay}_1, \textit{by}_1), \min(\textit{ay}_2, \textit{by}_2)] [max(ay1,by1),min(ay2,by2)],根据重叠部分的水平边投影到 x 轴上的线段长度和竖直边投影到 y 轴上的线段长度即可计算重叠部分的面积。只有当两条线段的长度都大于 0 时,重叠部分的面积才大于 0,否则重叠部分的面积为 0。

代码:

#include<iostream>
#include<cmath>
using namespace std;

#define x first
#define y second
typedef pair<int,int>PII;

struct node{
    PII ld , rt;
}a ,b,c;
int main(){
    cin>>a.ld.x>>a.ld.y>>a.rt.x>>a.rt.y;
    cin>>b.ld.x>>b.ld.y>>b.rt.x>>b.rt.y;
    cin>>c.ld.x>>c.ld.y>>c.rt.x>>c.rt.y;
    PII lt = {c.ld.x , c.rt.y};
    int ans = get_area(a) + get_area(b);
    ans -= max(min(a.rt.x , c.rt.x) - max(a.ld.x,c.ld.x) , 0) * max(min(a.rt.y , c.rt.y) - max(a.ld.y,c.ld.y), 0);
    ans -= max(min(b.rt.x , c.rt.x) - max(b.ld.x,c.ld.x) , 0) * max(min(b.rt.y , c.rt.y) - max(b.ld.y,c.ld.y), 0);
    cout<<ans<<endl;
	return 0;
}

阻挡广告牌 II

题目:题目链接

解题思路:
可以减少使用面积总共分为以下四种情况:
在这里插入图片描述
我们可以发现,如果是宽度大于,那么我们相交的矩形右上角和最下角的纵坐标与割草机的是一样的。同理如果是长度覆盖,则是x一样。因此我们借助上一题求出相交矩形左下角和右上角的坐标,如果满足上面说的,一个我们就用割草机广告的面积减去相交矩形的面积,这里如果完全覆盖结果为0符合题意,如果不相交得到割草机广告的面积也符合。其余就直接输出割草机广告的面积即可。

代码:

#include<iostream>
#include<cmath>
using namespace std;

#define x first
#define y second
typedef pair<int,int>PII;

struct ret{
    PII ld , rt;
}a ,b;

int get(PII a ,PII b){
    return (b.y - a.y) * ( b.x - a.x);
}

int main(){
    cin>>a.ld.x>>a.ld.y>>a.rt.x>>a.rt.y;
    cin>>b.ld.x>>b.ld.y>>b.rt.x>>b.rt.y;
    
    int lx = max(a.ld.x , b.ld.x) , rx = min(a.rt.x , b.rt.x);
    int dy = max(a.ld.y , b.ld.y) , uy = min(a.rt.y , b.rt.y);
    if((lx == a.ld.x || rx == a.rt.x)&& uy == a.rt.y && dy == a.ld.y ) // 覆盖左右部分
        cout<< get(a.ld ,a.rt) - max((rx - lx) , 0) * max((uy - dy),0)<<endl;
    else if((dy == a.ld.y || uy == a.rt.y)&& rx == a.rt.x && lx == a.ld.x)
        cout<<get(a.ld ,a.rt) - max((rx - lx) , 0) * max((uy - dy),0)<<endl;
    else cout<<get(a.ld,a.rt)<<endl;
    
    return 0;
}

传送

题目:题目链接

解题思路:
分类讨论,如果转送门在内部那么我们一定使用。其余有以下三种情况
在这里插入图片描述
这三种情况,转送门是可能对我们有用的。也就是我们需要花费一些距离去转送门之后获得的收益更多。我们只需要在判断情况后输出min即可。

代码:

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

int a ,b ,x,y;

int main(){
    cin>>a>>b>>x>>y;
    if(x > y)swap(x, y);
    if(a > b)swap(a,b);
    if(x>=a  && y <= b)cout<< x - a + b - y<<endl;// 在内部
    else if(x < a && y > b )cout<<min(b-a ,(a - x + y - b))<<endl; // 3
    else if(x <= a && y>= a && y <= b )cout<<min(b-a , a - x + b - y)<<endl; //1
    else if(y >= b && x >= a && x <= b)cout<<min(b-a , x - a + y - b)<<endl; // 2
    else 
        cout<<b-a<<endl;
    return 0;

}

组队井字游戏(模拟 + 技巧)

题目:题目

解题思路

  1. 我们要解决的是能快速辨别出,一行,一列,对角线中相同元素个数。
  2. 对于一对奶牛,我们在记录的时候不能重复。
  3. 对于第一个问题,我们利用set去重的特性,如果我们将三个元素插入set后大小变为1,说明有三个相同的元素,如果是2就是有两个相同元素。
  4. 对于第二个问题,我们以元素个数做下标,将该大小的set,压入set中。

代码

#include<iostream>
#include<set>
#include<vector>
#include<string>
using namespace std;
#define x first
#define y second

const int N =  4;
typedef set<char> SC;
typedef pair<int,int>PII;
string s[N];
set<SC>wo[N];
int n = 3;

void insert(vector<PII>cow)
{
    SC co;
    for(auto c : cow)
        co.insert(s[c.x][c.y]);
    wo[co.size()].insert(co); // 加入分配的牛
}
int main(){
    for(int i = 0 ; i < n; ++i)cin>>s[i];
    
    for(int i = 0 ; i < n ; ++i)insert({{i,0},{i,1},{i,2}}); // 行
    
    for(int j = 0 ; j < n ; ++j)insert({{0,j},{1,j},{2,j}}); // 列
    
    insert({{0,0},{1,1},{2,2}}); // 主对角线
    
    insert({{0,2},{1,1},{2,0}}); // 副对角线
    
    cout<<wo[1].size()<<endl<<wo[2].size()<<endl;
    
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落春只在无意间

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值