グラフの緊張、パートI:波状のひも


21

ドメイン[ -3,3 ]で関数f(x)= sin(πx)+ 0.5 sin(3πx)をプロットしてみましょう。これは、ボード上にあるゆるいひもとして解釈できます。それでは駆動させ、N位置でボードに釘を(X 1、Y 1(X N、Y NX I ∈(-3,3)Y iは ∈[-1,1] 。文字列の最後に位置(-3,0)(3,0)にある2つのアイレットがあると想像してください。これで、紐の端を取り、紐がぴんと張るまでアイレットに通すことができます。これにより、グラフが区分的線形関数に変形されます。

いくつかの写真が役立つ場合があります。で8本の釘を取り、(-0.5、0.8)、(0.5、0.4)、(1.2、-0.9)、(-2.5、-0.9)、(-1.2、0.2)、(-2.8、-0.7) (1.5、-0.6)、(1.8、-0.8) 。次の3つのプロットは、上記のプロセスを示しています。

ここに画像の説明を入力してください

大きなバージョンの場合:右クリック->新しいタブで開く

また、文字列を視覚化するのが困難な場合のストリングの引き締めのアニメーションを次に示します。

ここに画像の説明を入力してください

チャレンジ

「爪」のリスト(これは必ずしもソートされているわけではありません)が与えられた場合、上記の関数fの形状から始まる場合、それらの爪とピンと張った文字列をプロットします。

プログラムまたは関数を作成し、STDIN、ARGV、または関数引数を介して入力を取得できます。結果を画面に表示するか、画像をファイルに保存できます。

結果がラスタライズされる場合、少なくとも幅300ピクセル、高さ100ピクセルである必要があります。(-3、-1.1)から(3,1.1)までの座標範囲は、画像の水平および垂直範囲の少なくとも75%をカバーする必要があります。xyの長さスケールは同じである必要はありません。爪(少なくとも3x3ピクセルを使用)と文字列(少なくとも1ピクセルの幅)を表示する必要があります。軸を含めても含めなくてもかまいません。

色は選択できますが、少なくとも2つの区別できる色が必要です。1つは背景用、もう1つは爪と文字列用です(ただし、色は異なる場合があります)。

すべての釘はfから少なくとも10 -5ユニット離れていると仮定できます(そのため、浮動小数点の不正確さを心配する必要はありません)。

これはコードゴルフなので、最短の回答(バイト単位)が勝ちです。

その他の例

さらに2つの(簡単な)例があります。

{{-2.5, 1}, {-1.5, -1}, {-0.5, 1}, {0.5, -1}, {1.5, 1}, {2.5, -1}}

ここに画像の説明を入力してください

(文字列はx軸と一致します。)

{{-2.7, -0.5}, {-2.3, -0.5}, {-1.7, 0.5}, {-1.3, 0.5}, {-0.7, -0.5}, {-0.3, -0.5}, {0.5, 1}, {1.5, -1}, {2.5, 1}}

ここに画像の説明を入力してください

別のチャレンジが必要ですか?

パートIIです!


爪が左から右にソートされていると仮定できますか?
2014

@エルああ、良いキャッチ。最初から指定していないので、いいえ。それを明確にします。
マーティンエンダー14

回答:


8

Python +ピカイロ727 708 608、+ PyLab、383

from pylab import*
def f(N):
 def P(u,w,N):
    T=lambda v,p:(C(v-u,p-u)>0)==(C(w-v,p-v)>0)==(C(u-w,p-w)>0);M=[(i,n)for i,n in enumerate(N)if T(V([n[0],sin(pi*n[0])+sin(3*pi*n[0])/2]),n)]
    if M:i,n=max(M,key=lambda n:C(n[1]-u,w-u)**2);M=P(u,n,N[:i])+[n]+P(n,w,N[i+1:])
    return M
 V=array;C=cross;a=V([3,0]);plot(*zip(*([-a]+P(-a,a,map(V,sorted(N)))+[a])));N and scatter(*zip(*N));show()

f([(-2.8,-0.7),(-2.5,-0.9),(-1.2,0.2),(-0.5,0.8),(0.5,0.4),(1.2,-0.9),(1.5, -0.6),(1.8, -0.8)])

例1

使い方

緊張した文字列が2つのポイントABを通過することがわかっていると仮定します(常に
A =(-3、0)B =(3、0)で開始できます)。間の最短経路 A及びB理想的であり、線分AB。ただし、関数(sinπx+ ...)およびABで囲まれた領域に爪がある場合、少なくとも1つは文字列をブロックする必要があります。特に、当該領域内のABから最も離れた爪は、ストリングをブロックする必要があります。したがって、Cがこの釘である場合、ピンと張った文字列はAおよびBに加えて、C。これで、セグメントACおよびCBに対してプロセスを繰り返し、最終的には爪が介在しなくなるまでこの方法で続行できます。 図1

これは、各ステップで線形スキャンを行うバイナリ分割統治アルゴリズムであるため、O(n log n)の最適な複雑度とO(n 2)の最悪の複雑度を持ちます


ポイントのリストが空の場合、エラーになります。しかし、それ以外のものは明らかに絶望的です!
feersum 14

@feersum良いキャッチ。一定。
2014

3

Python + pylab、576バイト

アルゴリズム:

問題を(-3、0)から3、0)までの最短経路を見つけることと解釈し、経路上の点とf(x)上の点をつなぐ垂直線分が決して爪と交差しないようにしました。 少なくとも1つの釘が存在する

xで、そのxの釘によって与えられる最小の上限と最大の下限を見つけます。これらの境界に加えて開始点と終了点で与えられる点がグラフ上の頂点であると考えてください。2つの頂点間のユークリッド距離によって与えられる重みを持つエッジを追加します。エッジ間の線分が、各x座標の上限と下限内に収まる場合に限ります。このグラフで最短経路を見つけます。

27のランダムポイントの例:

(-0.367534, -0.722751), (-0.710649, -0.701412), (1.593101, -0.484983), (1.771199, 0.681435), (-1.878764, -0.491436), (-0.061414, 0.628570), (-0.326483, -0.512950), (0.877878, 0.858527), (1.256189, -0.300032), (1.528120, -0.606809), (-1.343850, -0.497832), (1.078216, 0.232089), (0.930588, -0.053422), (-2.024330, -0.296681), (-2.286014, 0.661657), (-0.009816, 0.170528), (2.758464, 0.099447), (-0.957686, 0.834387), (0.511607, -0.428322), (-1.657128, 0.514400), (1.507602, 0.507458), (-1.469429, -0.239108), (0.035742, 0.135643), (1.194460, -0.848291), (2.345420, -0.892100), (2.755749, 0.061595), (0.283293, 0.558334), 

ラメの例

ゴルフ

for j in R(i&~1)ループ内のインデントのいくつかのスペースとして表示されるものは、実際にはタブです。

from pylab import*
P=((3,0),(-3,0))+input()
X=sorted(set(zip(*P)[0]))
l=len(X)*2
if l>4:scatter(*zip(*P[2:]))
f=lambda x:sin(pi*x)+sin(3*pi*x)/2
B=[[max([-9]+[p[1]for p in P if x==p[0]and p[1]<f(x)]),min([9]+[p[1]for p in P if x==p[0]and p[1]>f(x)])]for x in X]
b=zeros(l);b[2:]=inf
v=list(b)
R=range
for i in R(l):
 for j in R(i&~1):
    A=B[j/2][j&1];D,d=B[i/2][i&1]-A,X[i/2]-X[j/2];K=1;c=b[j]+norm((d,D))
    for k in R(j/2+1,i/2):C=A+D/d*(X[k]-X[j/2]);K&=C<B[k][1];K&=C>B[k][0]
    if(c<b[i])&K:b[i]=c;v[i]=j,(X[j/2],A)
l-=2
s=P[:1]
while l/2:l,p=v[l];s+=(p,)
plot(*zip(*s))
show()

非ゴルフ

from pylab import*
P = input()
Xn,Yn = zip(*P)
X = set(Xn+(3,-3))
f = lambda x:sin(pi*x)+sin(3*pi*x)/2
ylb = {x: max([-9]+[p[1] for p in P if p[0] == x and p[1] < f(x)]) for x in X}
yub = {x: min([9]+[p[1] for p in P if p[0] == x and p[1] > f(x)]) for x in X}
ylb[-3] = yub[3] = ylb[3] = 0
X = sorted(X)
l = len(X)
best = zeros((l,2))
best[1:] = inf
prev = [ [0,0] for i in range(l) ]
for i in range(l): # calculate min path to X[i] lb or ub
  for ib in 0,1:
    for j in range(i): # point to come from
      for jb in 0,1:
          Y2, Y1 = (ylb, yub)[ib][X[i]], (ylb, yub)[jb][X[j]]
          dy,dx = Y2 - Y1, X[i] - X[j]
          if all([Y1 + dy/dx*(x - X[j]) < yub[x] and Y1 + dy/dx*(x - X[j]) > ylb[x] for x in X[j+1:i]]):
             c = best[j][jb] + (dy**2+dx**2)**.5
             if c < best[i][ib]:
                 best[i][ib] = c
                 prev[i][ib] = j, jb, (X[j], Y1)
j, jb = l-1,0
pts = [(3,0)]
while j:
    j, jb, p = prev[j][jb]
    pts += [p]
plot(*zip(*pts))
scatter(Xn,Yn)
show()

PyLabは間違いなく賢く選択:)だった
エルは
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.