LoginSignup
1
1

More than 5 years have passed since last update.

凸頂点の数

Last updated at Posted at 2016-04-02

幾何はきついのですよ>_<
まあ、平面図形は空間図形よりはましですが。

前提

  • まず、枠ごとに辺を割り振る(mapping)。このとき、反時計回りに繋がるように注意する。
  • 1aは[[0,0],[1,0],[2,0],[3,0],[2,19],[1,19],[0,0]].each_cons(2).to_aとなる。

最初の方針

  • 重複している辺を取り除く。
  • 残った辺について閉路を検出する。辺自体が反時計回りという情報を持っているので、辺の集合の前側(edges[i][0])だけ見れば良い。
  • それぞれの閉路について、x,y座標を算出し、ベクトルに変換、隣接したベクトルの外積を計算する。外積が正なら180°未満の頂点である。
    • 鈍角・鋭角ではなく凸か凹かなので内積ではなく外積。
  • ドーナツ型の場合、内側の閉路が検出されることがある。しかし、 この閉路は時計回りになっている。 したがって、外積の符号は逆になる。外積が正の個数を数えればよいのは変わらないのである。

新しい方針

  • しかし、これだけのものを60分でその場で実装できるはずはない。あくまで帰宅後の清書である。
  • ロスタイム中に、 頂点数が1個ならば採用すべき頂点である ことがわかった。言い換えれば、伸びている辺が2本、である。
  • ただし、00が含まれる場合は一番内側の頂点を除けば良い。

コード

清書含みます。変数名も多少まともに。

tyama_henae03.rb
#!/usr/bin/ruby
#http://qiita.com/Nabetani/items/b8bf742d278c6cf501aa
#http://nabetani.sakura.ne.jp/hena/orde03nofconv/

D=[0,1,1,0,0,1,1,0,0,1]
Vertex=D.each.with_index(1).map{|e,r|
    20.times.map{|i|Complex(r*Math.cos(-(2*i+e)*Math::PI/20),r*Math.sin(-(2*i+e)*Math::PI/20))}
}
def mapping(s)
    if s=='00'
        (20.times.flat_map{|i|[[0,i],[1,i]]}+[[0,0]]).each_cons(2).map(&:reverse)
    else
        n,m=s[0].to_i-1,s[1].ord-97
        f=n%2
        [
            [n*2,(m+n/2)%20],
            [n*2+1,(m+n/2+f)%20],
            [n*2+2,(m+n/2+f)%20],
            [n*2+3,(m+n/2)%20],
            [n*2+2,(m+n/2-(f^1))%20],
            [n*2+1,(m+n/2-(f^1))%20],
            [n*2,(m+n/2)%20]
        ].each_cons(2).to_a
    end
end

STDOUT.sync=true
while gets
    data=$_.chomp.scan(/../)
    if false #どちらでも通ります
        h=Hash.new(0)
        edges=data.flat_map{|e|mapping(e)}
        edges.map(&:sort).each{|e|e.each{|f|h[f]+=1}}
        r=h.select{|k,v|v==2}.map(&:first)
        if data.include?('00')
            r.reject!{|x,y|x==0}
        end
        p r.size
    else
        h=Hash.new{|h,k|h[k]=[]}
        data.flat_map{|e|mapping(e)}.each{|e|h[e.sort]<< e}
        edges=h.select{|k,v|v.size==1}.flat_map(&:last)
        r=0
        while !edges.empty?
            cycle=[edges.shift]
            while cycle.last[1]!=cycle.first[0]
                edges.size.times{|i|
                    if edges[i][0]==cycle.last[1]
                        cycle<<edges[i]
                        edges.delete_at(i)
                        break
                    end
                }
            end
            cycle=cycle.map{|e|e.map{|n,m|Vertex[n][m]}}.map{|e,f|
                f-e
            }
            r+=cycle.size.times.count{|i|
                # 外積を手早く計算したくてComplexにした
                (cycle[i].conj*cycle[(i+1)%cycle.size]).imag>0
            }
        end
        p r
    end
end
1
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1