COCI CONTEST #3 29.11.2014 T3 SILUETA

本文介绍了一种算法,用于复原由多个重叠矩形构成的摩天大楼轮廓,并计算轮廓线的周长(不含底边)。通过预处理得到每个x坐标的最高点,遍历这些点并构建地图,最终输出地图及轮廓周长。

第三题:
题目描述
有一个画家,画了n栋摩天大楼。(实际上只有远远望去的轮廓)。每栋楼都是一个矩形,有些矩形是重叠在一起的。所有的矩形的底边都在一条直线上。很不幸,画被烧毁了。但是记得每个矩形的位置和高度,现在请你复原这幅画,并求出矩形的轮廓线的周长(不包含底边)。
输入
第一行:给出一个整数n表示有n栋大楼。(n<10000)
接下来有n行,每行三个整数Li,Ri,Hi。表示第i栋楼的左下角坐标为(Li,0),右上角坐标为(Ri,Hi)。(1<=Li,Ri,Hi<=1000,3<=Ri-Li<=1000)
输出
第一行为一个整数,表示摩天大楼的周长。
接下来h+1行,为复原的地图。
其中h表示最高的那栋楼的高度。
‘#’表示摩天大楼的轮廓,其中x轴用‘*’表示,其他区域用’.’表示。具体看样例。
样例输入
3
1 5 4
7 11 3
9 13 5
样例输出
28
这里写图片描述
一般难度。
可以预处理一个h[],h[i]表示当x=i时,y最大是多少。
如样例,h[]的值应该是
i 1 2 3 4 5 6 7 8 9 10 11 12
h[i] 4 4 4 4 0 0 3 3 5 5 5 5
然后扫一遍h[i]数组。
对于一个i,如果h[i]不为0,那么在对应的高度输出#号。
如果h[i-1]比h[i]低,那么应该在i处从h[i-1]的高度一直输出#直到高度变为h[i]-1。
如果h[i-1]比h[i]高,那么应该在i-1处从h[i]的高度一直输出#直到高度变为h[i-1]-1。
有一个神奇的现象,如果像我刚才那样输出#,那么每输出一个#,ans++,周长就是ans。
其实应该这样:
扫一遍图案,每有一个#,ans++;每有一个外凸的角,ans++;每有一个内凹的角,ans–。
或者搜索也可以。
30分。
因为求错周长了。
考试的时候以为所有的不规则图形都是可以平移边,变成一个规则矩形的周长
但是只有阶梯状的是这样,内凹的不是。
而样例全是阶梯状的。。。

#include<iostream>
#include<cstdio>
using namespace std;
bool map[1005][1005];
int h[1005],minl=1005,maxr,maxh,n,ans;
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;++i)
    {
        int li,ri,hi;
        scanf("%d%d%d",&li,&ri,&hi);
        minl=min(li,minl);
        maxr=max(ri,maxr);
        maxh=max(hi,maxh);
        for(int i=li;i<ri;++i)
            h[i]=max(h[i],hi);
    }
    for(int i=minl;i<=maxr;++i)
    {
        if(h[i])map[h[i]][i]=1,ans++;
        if(h[i]>h[i-1])
            for(int j=h[i-1];j<h[i];++j)
                map[j][i]=1,ans++;
        if(h[i]<h[i-1])
            for(int j=h[i];j<h[i-1];++j)
                map[j][i-1]=1,ans++;
    }
    printf("%d\n",ans);
    for(int i=maxh;i>=0;--i)
    {
        for(int j=minl;j<maxr;++j)
            i==0?printf("*"):printf("%c",map[i][j]?'#':'.');
        puts("");
    }
}
COCI 2020/2021竞赛的第一场中,第1题“Patkice”要求解决一个与鸭子在网格中行走并计算路径相关的问题。题目大意是:给定一个由字符组成的二维网格,表示鸭子的移动规则,鸭子只能沿着特定方向的路径行走,并且不能回头。目标是根据输入条件判断是否存在从起点到终点的唯一路径,或者是否无法确定路径。 ### 题目解析 问题描述中包含三种不同的地形字符: - `.` 表示可以通过的空地。 - `#` 表示障碍物,不可通过。 - 字符 `D`, `L`, `R`, `U` 分别表示该位置是起点、向左走、向右走、向上走的指令格。 鸭子每次必须按照当前所在格子的指令方向移动一步,直到无路可走或到达终点。因此,需要检查是否存在唯一的路径从起点到达终点,并且确保没有歧义(即每一步都没有多个可能的方向)。 ### 解法思路 1. **建模为图遍历问题**:可以将整个网格看作一个有向图,每个可通行的格子是一个节点,而其指令方向决定了下一步要走到哪个节点。 2. **深度优先搜索(DFS)或广度优先搜索(BFS)**:从起点出发,模拟鸭子的移动过程。如果某一步存在两个或以上可选方向,则说明路径不唯一;如果中途无法继续移动且未到达终点,则输出无法到达。 3. **边界处理**:需要注意避免越界访问以及循环路径(例如来回跳跃)的情况。 ### 示例代码 以下是一个可能的解法实现: ```cpp #include <bits/stdc++.h> using namespace std; const int MAXN = 105; char grid[MAXN][MAXN]; bool visited[MAXN][MAXN]; int n, m; // 将方向字符转换为坐标增量 pair<int, int> direction(char c) { if (c == &#39;U&#39;) return {-1, 0}; if (c == &#39;D&#39;) return {1, 0}; if (c == &#39;L&#39;) return {0, -1}; if (c == &#39;R&#39;) return {0, 1}; return {0, 0}; // 起点 } // DFS函数 void dfs(int x, int y, bool &found, bool &ambiguous) { if (visited[x][y]) { return; // 避免重复访问 } visited[x][y] = true; auto [dx, dy] = direction(grid[x][y]); if (dx == 0 && dy == 0) { // 当前是终点 found = true; return; } int nx = x + dx; int ny = y + dy; if (nx >= 0 && nx < n && ny >= 0 && ny < m && grid[nx][ny] != &#39;#&#39;) { dfs(nx, ny, found, ambiguous); } else { // 无法继续前进 return; } } int main() { cin >> n >> m; pair<int, int> start; for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { cin >> grid[i][j]; if (grid[i][j] == &#39;L&#39; || grid[i][j] == &#39;R&#39; || grid[i][j] == &#39;U&#39; || grid[i][j] == &#39;D&#39;) { // 检查是否有歧义路径 auto [dx1, dy1] = direction(grid[i][j]); int nx1 = i + dx1; int ny1 = j + dy1; if (nx1 >= 0 && nx1 < n && ny1 >= 0 && ny1 < m && grid[nx1][ny1] != &#39;#&#39;) { // 存在另一个可能的方向 cout << "AMBIGUOUS" << endl; return 0; } } if (grid[i][j] == &#39;L&#39; || grid[i][j] == &#39;R&#39; || grid[i][j] == &#39;U&#39; || grid[i][j] == &#39;D&#39;) { start = {i, j}; } } } bool found = false; bool ambiguous = false; memset(visited, 0, sizeof(visited)); dfs(start.first, start.second, found, ambiguous); if (!found) { cout << "DEAD END" << endl; } else { cout << "UNIQUE" << endl; } return 0; } ``` ### 复杂度分析 - 时间复杂度:最坏情况下为 $O(N \times M)$,其中 $N$ 和 $M$ 是网格的行数和列数。 - 空间复杂度:主要使用了一个访问数组来记录已访问的格子,空间复杂度为 $O(N \times M)$。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值