ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

洛谷P2864

2022-02-26 17:31:23  阅读:161  来源: 互联网

标签:... 洛谷 int qx qy P2864 fi forest



title: "有点意思的蓝题"
author: Sun-Wind
date: February 26,2022

来一发在洛谷的第一篇题解

解析

首先从原点出发回到原点会形成一个环

要计算在环上的路程,首先我们要破环

利用建墙法破环

可以选取任意一个边缘上的树,往上或者往下或者往左往右建立一堵墙‘|’

这样利用bfs搜索的时候无法穿过这堵墙

如下所示我们在第一棵树上面建了一堵墙,隔绝了左右两个部分

...|...
...|...
...X...
..XXX..
...XXX.
...X...
......*

从起点到相邻着墙左边的点的最短距离+到相邻着墙右边点的最短距离+在墙上走的距离之和(因为实际上我们还是要走墙这一段距离),求其最小值就是我们需要的答案

解法正确性证明

假设我们已经通过这种方法求出来一个解,存在比这种解法更优的解法

首先我们知道这种更优的解法也一定会穿过墙,并且对应墙相邻左右的两个点

我们的这种解法其中一种情况也同样对应墙两边相邻左右的两个点,并且与更优解的这两个点对应

(原解法)
设x1是起点到墙左边这个点的距离,x2是到右边点的距离,x3是中间在墙上经过的距离

(更优解)
x11与x22,x33和上面x1,x2,x3定义一样,

那么一定有x1 + x2 < x11 + x22

如果更优解存在,那么x3 > x33

说明在墙上的距离存在比x3更小

然而我们所想的方法求得是x1 + x2 + x3 的最小值

如果x33 比x3更小,那么显然x1+x2+x33才是我们所想方法的解

这和假设相矛盾

即可得证

代码

#include<iostream>
#include<utility>
#include<queue>
#include<cmath>
using namespace std;
typedef long long ll;
#define fi(i,a,b) for(int i = a; i <= b; ++i)
#define fr(i,a,b) for(int i = a; i >= b; --i)
#define x first
#define y second
#define sz(x) ((int)(x).size())
#define pb push_back
using pii = pair<int,int>;
//#define DEBUG
int dis[55][55];//最短路数组
char forest[55][55];//样例数据
bool vis[55][55];//标记是否访问过
int qx,qy;//第一棵树
int sx,sy;//起始点
int n,m;
int res = 0x3f3f3f3f;//答案
int dx[8] = {1,1,1,0,0,-1,-1,-1};
int dy[8] = {1,0,-1,1,-1,1,0,-1};//方向数组
struct point{
    int x,y,k;
};//分别表示坐标和最短路
void bfs(int x,int y){
    queue<point> que;
    que.push({sx,sy,0});
    vis[sx][sy] = true;
    while(!que.empty()){
        point temp = que.front();
        que.pop();
        fi(i,0,7){
            int p = temp.x + dx[i];
            int q = temp.y + dy[i];
            if(p >= 1 && p <= n && q >= 1 && q <= m && forest[p][q] == '.' && !vis[p][q]){
                vis[p][q] = true;
                dis[p][q] = temp.k + 1;//bfs第一个访问到得就是最短路
                que.push({p,q,dis[p][q]});
            }
        }
    }
    return;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n >> m;
    int bk = 0;
    fi(i,1,n) fi(j,1,m) {
        cin >> forest[i][j];
        if(forest[i][j] == 'X' && !bk){
            qx = i,qy = j;
            bk = 1;
        }//标记第一颗树
        else if(forest[i][j] == '*'){
            sx = i,sy = j;
        }
    }

    fi(i,1,qx-1){
        forest[i][qy] = '|';
    } //把第一棵树上面得所有点变成墙

    bfs(sx,sy);
    
    fi(i,1,qx) fi(j,1,qx){//循环到qx因为可以斜着走
        if(forest[i][qy-1] == '.' && forest[j][qy+1] == '.')//循环墙得左右两边得点
            res = min(dis[i][qy-1] + dis[j][qy+1] + abs(i-j) + 1,res);
    }
    cout << res +1 << endl;//加上原点
#ifdef DEBUG
    //freopen(D:\in.txt,r,stdin);
#endif
    return 0;
}

标签:...,洛谷,int,qx,qy,P2864,fi,forest
来源: https://www.cnblogs.com/Sun-Wind/p/15939914.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有