欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[模拟] UVa177 折纸痕(点,线的绕点旋转)

程序员文章站 2022-07-07 15:33:53
...

题目

[模拟] UVa177 折纸痕(点,线的绕点旋转)

思路

  1. 本题的思路其实通过观察图形,很容易想出来的。即维护两个点s和rot,每次将整个图形绕rot点顺时针选择90度,并将rot点更新为旋转后的s点即可。
  2. 关键在于横竖线的表达与数据结构问题。陈锋所采用的方法是:用start, end, vertical来描述一条线,随后对线的操作即为对start, end两个点的操作,以及极其重要的normalize函数。
  3. 对于平面几何点绕点旋转的方法:
    • 点p,以点r为中心,顺时针旋转90度
pv = p - r;  //以r为中心,建立相对坐标系
p' = Point(pv.y, -pv.x);
p' += r;   //相对坐标系用完,还原
  • 点p,以点r为中心,逆时针旋转90度
pv = p - r;
p' = Point(-pv.y, pv.x);
p' += r;

4.代码的输出,实现了由线到点的转化,还是值得看一看的,这类横线竖线的问题UVA上有很多。
5.陈锋大佬代码中,对于各种数据结构的声明和运用,能让代码更易读,debug起来也方便,应该学习。

代码

// Paper Folding, UVa177
// 陈锋,侵删
#include <cassert>
#include <algorithm>
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <map>
#define _for(i,a,b) for( int i=(a); i<(b); ++i)

using namespace std;

struct Point {
  int x, y;
  Point(int x=0, int y=0):x(x),y(y) {}
};
typedef Point Vector;

Vector operator+ (const Vector& A, const Vector& B) { return Vector(A.x+B.x, A.y+B.y); }
Vector operator- (const Point& A, const Point& B) { return Vector(A.x-B.x, A.y-B.y); }
Vector operator* (const Vector& A, int p) { return Vector(A.x*p, A.y*p); }
bool operator== (const Point& a, const Point &b) { return a.x == b.x && a.y == b.y; }
bool operator!= (const Point& a, const Point &b) { return !(a==b); }
bool operator< (const Point& p1, const Point& p2) { return p1.x < p2.x || (p1.x == p2.x && p1.y < p2.y); }
ostream& operator<<(ostream& os, const Point& p) { 
    return os<<p.x<<','<<p.y;
}

// p围绕r顺时针旋转90度,返回旋转后的点
Point rotate(const Point& p, const Point& r) {
    Vector pv = p - r;
    Point ans = r + Vector(pv.y, -pv.x);
    return ans;
}

const int MAXN = 13;
struct Line {
    Point start, end;
    bool vertical;

    // 围绕r顺时针旋转90度
    Line rotate(const Point& r) {
        Line ret;
        ret.start = ::rotate(start, r);
        ret.end = ::rotate(end, r);
        return ret;
    }
    // 规整,保证start在end的左边或者上边
    void normalize() {
        assert(start != end);
        assert(start.x == end.x || start.y == end.y);
        vertical = (start.x == end.x);
        if(vertical) {
            if(start.y > end.y) swap(start.y, end.y);
        } else {
            if(start.x > end.x) swap(start.x, end.x);
        }
    }
};

int n, LineCnt;
vector<Line> lines;

int main()
{    
    lines.reserve(1<<MAXN);
    while(cin>>n&&n) {
        Line l;
        l.end = Point(1, 0);
        l.vertical = false;
        lines.clear();
        lines.push_back(l);
        int maxY = l.start.y, minY = l.start.y,
            minX = l.start.x, maxX = l.end.x;

        Point s = l.start, rot = l.end;
        _for(i, 0, n) {
            int sz = lines.size();            
            _for(j, 0, sz) {
                Line nl = lines[j].rotate(rot);
                nl.normalize();
                lines.push_back(nl);
            }
            rot = rotate(s, rot);
        }

        map<Point, char> pc;
        for(auto& l : lines) {
            Point& lp = l.start;
            lp.x *= 2;
            if(l.vertical) lp.x--;
            minX = min(lp.x, minX);
            maxX = max(lp.x, maxX);
            minY = min(lp.y, minY);
            maxY = max(lp.y, maxY);
            pc[lp] = l.vertical ? '|' : '_';
        }

        // cout<<"minX = "<<minX<<endl;
        string buf;
        for(int y = maxY; y >= minY; y--) {
            buf.clear();
            for(int x = minX; x <= maxX; x++) {
                Point p(x,y);
                if(pc.count(p)) buf += pc[p];
                else buf += ' ';
            }
            while(*(buf.rbegin()) == ' ') buf.erase(buf.size()-1);
            cout<<buf<<endl;
        }

        cout<<"^"<<endl;
    }
    return 0;
}
相关标签: 模拟