ความตึงเครียดบนกราฟตอนที่ II: แถบยาง


13

นี่เป็นความท้าทายครั้งที่สองในสองเรื่องเกี่ยวกับ "ฟังก์ชันดึงตึง" นี่คือง่ายเล็กน้อย Part I

Let 's ไดรฟ์เมตรเล็บเข้าไปในคณะกรรมการที่ตำแหน่ง(x 1 , y 1 )การ(x เมตร , y ม. ) มัดยางรัดไว้กับเส้นที่หนึ่งและเส้นสุดท้ายของเล็บเหล่านั้นและเหยียดรอบเล็บอื่น ๆ เช่นที่วงจะเคลื่อนที่ไปตามเล็บทั้งหมดตามลำดับ โปรดทราบว่าในตอนนี้แถบยางอธิบายฟังก์ชั่นพารามิเตอร์เชิงเส้น(x (t), y (t))ในขอบเขต 2D

ตอนนี้ขับไปอีกnเล็บเข้าไปในคณะกรรมการที่ตำแหน่ง(x 1 , y 1 )การ(x n , y n ) ถ้าตอนนี้เราเอาของเดิมเมตรเล็บยกเว้นคนแรกและครั้งสุดท้าย (ซึ่งปลายของยางที่มีการเชื่อมโยงกับ) ยางรัดจะสั้นลงจนกว่าจะมีการโกหกตึงรอบเล็บใหม่ที่ให้ผลผลิตค่อีกฟังก์ชั่นการเชิงเส้น

ยกตัวอย่างเช่นใช้m = 12เล็บเริ่มต้นที่ตำแหน่ง(0, 0), (2, -1), (3/2, 4/3), (7/2, 1/3), (11/2, 16/3), (1, 16/3), (0, 1), (7, -2), (3, 4), (8, 1), (3, -1), (11, 0)และn = 10เล็บเพิ่มเติมที่ตำแหน่ง(1, 1), (3, 1), (4, 4), (1, 3), (2, 2), (5, -1), (5, 0 ), (6, 2), (7, 1), (6, 0) สามแปลงต่อไปนี้แสดงกระบวนการที่อธิบายข้างต้น:

ป้อนคำอธิบายรูปภาพที่นี่

สำหรับรุ่นใหญ่: คลิกขวา -> เปิดในแท็บใหม่

และนี่คือแอนิเมชั่นของแถบยางรัดให้กระชับถ้าคุณมีปัญหาในการมองเห็น:

ป้อนคำอธิบายรูปภาพที่นี่

ความท้าทาย

ให้รายชื่อ "nails" สองรายการให้พล็อตยางรัดตึงรอบรายการที่สองหากเริ่มต้นจากการเคลื่อนที่ของเล็บทั้งหมดในรายการแรก

คุณสามารถเขียนโปรแกรมหรือฟังก์ชั่นและรับอินพุตผ่าน STDIN, ARGV หรืออาร์กิวเมนต์ของฟังก์ชัน คุณสามารถแสดงผลบนหน้าจอหรือบันทึกภาพเป็นไฟล์

หากผลลัพธ์เป็น rasterised จะต้องมีอย่างน้อย 300 พิกเซลในแต่ละด้าน ยางรัดสุดท้ายและเล็บจะต้องครอบคลุมอย่างน้อย 75% ของขอบเขตแนวนอนและแนวตั้งของภาพ สเกลความยาวของxและyต้องเท่ากัน คุณต้องแสดงเล็บในชุดที่สอง (ใช้อย่างน้อย 3x3 พิกเซล) และสตริง (กว้างอย่างน้อย 1 พิกเซล) คุณสามารถหรือไม่รวมแกน

สีเป็นตัวเลือกของคุณ แต่คุณต้องมีอย่างน้อยสองสีที่แตกต่าง: หนึ่งสำหรับพื้นหลังและหนึ่งสำหรับเล็บและสตริง (อาจมีสีที่แตกต่างกัน)

คุณอาจสันนิษฐานได้ว่าเล็บทั้งหมดในรายการที่สองอยู่ห่างกันอย่างน้อย 10 -5ยูนิตจากรูปร่างเริ่มต้นของแถบยาง (เพื่อให้คุณไม่ต้องกังวลเกี่ยวกับความไม่แม่นยำของจุดลอย)

นี่คือรหัสกอล์ฟดังนั้นคำตอบที่สั้นที่สุด (เป็นไบต์) ชนะ

ตัวอย่างเพิ่มเติม

นี่คืออีกสองตัวอย่าง:

{{1, 1}, {3, 3}, {2, 4}, {1, 3}, {4, 0}, {3, -1}, {2, 0}, {4, 2}}
{{2, 1}, {3, 2}, {1, 2}, {4, 1}}

ป้อนคำอธิบายรูปภาพที่นี่

{{1, 1}, {3, 1}, {3, 3}, {1, 3}, {1, 5}, {3, 5}, {-1, 3}, {-1, 0}, {3, 4}, {5, 1}, {5, -1}, {7, -1}, {3, 7}, {7, 5}}
{{0, 0}, {0, 2}, {0, 4}, {0, 6}, {2, 0}, {2, 2}, {2, 4}, {2, 6}, {4, 0}, {4, 2}, {4, 4}, {4, 6}, {6, 0}, {6, 2}, {6, 4}, {6, 6}}

ป้อนคำอธิบายรูปภาพที่นี่

และนี่คือตัวอย่างหนึ่งที่แสดงให้เห็นถึงความสำคัญของสองเล็บเริ่มแรกที่เหลืออยู่ ผลที่ควรจะและไม่ :

{{0, 0}, {0, 1}, {-1, 1}, {-1, -1}, {1, -1}, {1, 0}}
{{-0.5, 0.5}}

ป้อนคำอธิบายรูปภาพที่นี่

ขอบคุณ Ell ที่ให้ตัวอย่างนี้


@laurencevs สตริงหนึ่งมีค่าเดียวซึ่งทำให้สิ่งต่าง ๆ ง่ายขึ้นเนื่องจากมีทิศทางที่ชัดเจนในการประมวลผลฟังก์ชั่นและเล็บ อันนี้อาจมีลูปและคดเคี้ยวไปมาและรูปแบบของฟังก์ชั่นแตกต่างกันมาก (และตัวแปร) ซึ่งหมายความว่าการแก้ปัญหาควรจะแตกต่างกันมาก
Martin Ender

ผลลัพธ์ของสิ่งนี้คืออะไร
Ell

@Ell Ah กรณีทดสอบที่ดีมาก ฉันคิดว่าสำหรับความสอดคล้องมันควรจะเป็นbแต่ฉันต้องชี้แจงคำถามเกี่ยวกับเรื่องนั้น จะทำเช่นนั้นในไม่ช้า ขอบคุณ!
Martin Ender

คำตอบ:


11

Python + matplotlib, 688

from pylab import*
C=cross
P,M=eval("map(array,input()),"*2)
P,N=[[P[0]]+L+[P[-1]]for L in P,M]
W=[.5]*len(P)
def T(a,c,b):
 I=[(H[0]**2,id(n),n)for n in N for H in[(C(n-a,b-a),C(n-b,c-b),C(n-c,a-c))]if(min(H)*max(H)>=0)*H[1]*H[2]]
 if I:d=max(I)[2];A=T(a,c,d);B=T(d,c,b);return[A[0]+[d]+B[0],A[1]+[sign(C(c-a,b-c))]+B[1]]
 return[[]]*2
try:
 while 1:
    i=[w%1*2or w==0for w in W[2:-2]].index(1);u,a,c,b,v=P[i:i+5];P[i+2:i+3],W[i+2:i+3]=t,_=T(a,c,b);t=[a]+t+[b]
    for p,q,j,k in(u,a,1,i+1),(v,b,-2,i+len(t)):x=C(q-p,c-q);y=C(q-p,t[j]-q);z=C(c-q,t[j]-q);d=sign(j*z);W[k]+=(x*y<=0)*(x*z<0 or y*z>0)*(x!=0 or d*W[k]<=0)*(y!=0 or d*W[k]>=0)*d
except:plot(*zip(*P))
if M:scatter(*zip(*M))
show()

อ่านสองรายการคะแนนจาก STDIN

ตัวอย่าง

[(0, 0), (2, -1), (3.0/2, 4.0/3), (7.0/2, 1.0/3), (11.0/2, 16.0/3), (1, 16.0/3), (0, 1), (7, -2), (3, 4), (8, 1), (3, -1), (11, 0)]
[(1, 1), (3, 1), (4, 4), (1, 3), (2, 2), (5, -1), (5, 0), (6, 2), (7, 1), (6, 0)]

รูปที่ 1

มันทำงานอย่างไร

กุญแจสำคัญในการแก้ปัญหาคือการทำงานในขั้นตอนเล็ก ๆ ที่เพิ่มขึ้น แทนที่จะพยายามคิดออกว่าเกิดอะไรขึ้นเมื่อเราลบเล็บทั้งหมดในครั้งเดียวเรามุ่งเน้นที่ผลกระทบโดยตรงของการลบเล็บเพียงครั้งเดียว จากนั้นเราสามารถลบเล็บทีละตัวตามลำดับที่กำหนด

การทำงานที่เพิ่มขึ้นหมายความว่าเราต้องติดตามสถานะกลางของแถบยาง นี่คือส่วนที่ยุ่งยาก: เพียงแค่ติดตามว่าเล็บที่วิ่งผ่านวงดนตรีนั้นไม่เพียงพอ ในระหว่างขั้นตอนการถอดเล็บวงดนตรีจะได้รับบาดแผล ดังนั้นเมื่อวงดนตรีมีปฏิสัมพันธ์กับเล็บเราต้องติดตามจำนวนครั้งและในทิศทางที่มันล้อมรอบมัน เราทำโดยการกำหนดค่าให้กับเล็บแต่ละวงตามด้วย:

รูปที่ 2

โปรดทราบว่า:

  • เราเริ่มนับทันทีที่วงสัมผัสกับเล็บแม้ว่าเล็บจะไม่ส่งผลกระทบต่อรูปร่างของมัน จำได้ว่าเล็บของเราไม่มีมิติ ดังนั้นหากวงดนตรีสัมผัสกับเล็บเราจึงไม่สามารถบอกได้ว่าด้านใดของเล็บที่อยู่ในตำแหน่งเดียว - เราต้องติดตามว่ามันเคยเกี่ยวข้องกับแถบไหน

  • เราเก็บเล็บไว้รอบ ๆ ด้วยค่าศูนย์นั่นคือเล็บที่ใช้ แต่ไม่ได้ยึดวงไว้อีกต่อไปแทนที่จะถอดออกทันที ถ้าเราทำมันอาจทำให้เกิดปฏิกิริยาลูกโซ่ที่ไม่ได้รับการร้องขอในขณะที่เราพยายามรักษาผลของการแปลแต่ละขั้นตอน แต่เล็บที่มีค่าเป็นศูนย์จะถือว่ามีสิทธิ์ในการกำจัดซึ่งเป็นส่วนหนึ่งของกระบวนการที่ใหญ่กว่า

ตอนนี้เราสามารถอธิบายสิ่งที่เกิดขึ้นในแต่ละขั้นตอน:

  • เราเลือกเล็บที่จะลบออกจากเส้นทางปัจจุบันของวงดนตรี เล็บสามารถถอนได้ถ้าเป็นส่วนหนึ่งของเล็บชุดแรก (บันทึกสำหรับจุดสิ้นสุด) หรือถ้าค่าเป็นศูนย์

  • ทำท่าว่าเล็บที่อยู่ใกล้เคียงทั้งสองนั้นได้รับการแก้ไขแล้วเราจะหาว่าเล็บใดจากชุดที่สองหรือจุดปลายของวงดนตรีที่จะวิ่งผ่านเมื่อเล็บที่เลือกถูกลบออก (เราไม่ได้สนใจเล็บที่เหลือจาก ชุดแรกตั้งแต่ที่พวกเขาจะได้ในที่สุดทั้งหมดถูกลบออก.) เราจะทำในลักษณะคล้ายกับวิธีการแก้ Part I เล็บเหล่านี้ทั้งหมดอยู่ในด้านเดียวกันของวงดนตรีดังนั้นเราจึงกำหนดค่าทั้งหมด1หรือ-1ขึ้นอยู่กับด้านข้าง

  • เราอัปเดตคุณค่าของตะปูสองตัวที่อยู่ใกล้เคียงเพื่อสะท้อนการเปลี่ยนแปลงของเส้นทางของวงดนตรี (ส่วนที่ง่ายที่สุด!)

กระบวนการนี้จะทำซ้ำจนกว่าจะไม่มีตะปูเพื่อเอาออก:

รูปที่ 3

และนี่คือตัวอย่างที่ซับซ้อนมากขึ้นที่แสดงการพันวงรอบเล็บหลาย ๆ ครั้ง:

รูปที่ 4


! ที่น่าตื่นตาตื่นใจ สิ่งหนึ่งที่: กราฟิกเหล่านั้น rasterised หรือว่าพวกเขากราฟิกแบบเวกเตอร์? ในกรณีก่อนหน้านี้ฉันจะต้องชี้ให้คุณ "ระดับความยาวของ x และ y ต้องเท่ากัน" นอกจากนี้สิ่งที่คุณใช้ในการสร้างกราฟิกทั้งหมดที่คุณใช้ในคำอธิบายของคุณ matplotlib ด้วยหรือไม่
Martin Ender

ขอบคุณ! เอ่อ ... ตั้งแต่ matplotlib ขอฉันขนาดพล็อตบนบินฉันจะไปกับกราฟิกแบบเวกเตอร์ :) สำหรับภาพประกอบที่ผมใช้ส่วนใหญ่GeoGebra มันค่อนข้างแปลก แต่ก็ทำงานเสร็จแล้ว
Ell

ใช่แล้วถ้าคุณสามารถปรับขนาดได้ตามอำเภอใจก็ไม่เป็นไร ขอบคุณสำหรับลิงค์ฉันจะตรวจสอบว่า!
Martin Ender

4

Java - 1262 ไบต์

ฉันรู้ว่านี่อาจไม่ได้เล่นกอล์ฟมากเท่าที่ควร

อย่างไรก็ตามดูเหมือนว่าไม่มีใครอื่นกำลังก้าวขึ้นไปบนจานและตอบคำถามนี้ดังนั้นฉันจะ

ครั้งแรกคลาส "T" - ซึ่งเป็นระดับจุด - 57 ไบต์

class T{double x,y;public T(double a,double b){x=a;y=b;}}

และคลาสหลัก - 1205 ไบต์

import java.awt.Color;import java.awt.Graphics;import java.util.*;import javax.swing.*;class Q extends JPanel{void d(List<T>a,T[]z){JFrame t=new JFrame();int m=0;int g=0;for(T v:a){if(v.x>m)m=(int)v.x;if(v.y>g)g=(int)v.y;}for(T v:z){if(v.x>m)m=(int)v.x;if(v.y>g)g=(int)v.y;}t.setSize(m+20,g+20);t.setVisible(true);t.getContentPane().add(this);double r=9;while(r>1){r=0;for(int i=0;i<a.size()-1;i+=2){T p1=a.get(i),p2=new T((p1.x+a.get(i+1).x)/2,(p1.y+a.get(i+1).y)/2);a.add(i+1,p2);if(y(p1,p2)>r){r=y(p1,p2);}}}double w=15;List<T>q=new ArrayList<T>();while(w>3.7){w=0;q.clear();for(int e=0;e<a.size()-2;e++){T p1=a.get(e),u=a.get(e+1),p3=a.get(e+2),p2=new T((p1.x+p3.x)/2,(p1.y+p3.y)/2);w+=y(u,p2);int k=0;if(y(p1,a.get(e+1))<.5){a.remove(e);}for(T n:z){if(y(n,p2)<1){k=1;q.add(n);}}if(k==0){a.set(e+1,p2);}}}q.add(a.get(a.size()-1));q.add(1,a.get(0));p=z;o=q.toArray(new T[q.size()]);repaint();}T[]p;T[]o;double y(T a,T b){return Math.sqrt(Math.pow(b.x-a.x,2)+Math.pow(b.y-a.y,2));}public void paintComponent(Graphics g){if(o!=null){for(int i=0;i<o.length-1;i++){g.drawLine((int)o[i].x,(int)o[i].y,(int)o[i+1].x,(int)o[i+1].y);}g.setColor(Color.blue);for(T i:p){g.fillOval((int)i.x-3,(int)i.y-3,6,6);}}}}

ตัวอย่าง:

ป้อนคำอธิบายรูปภาพที่นี่

หากต้องการเรียกใช้ให้เรียกฟังก์ชัน "d" พร้อมกับ List of points และอาเรย์ของเล็บ (ใช่ฉันรู้ว่าแปลก) มันทำอะไร:

  • สร้างรายการของจุดที่แสดงถึงเส้น - นั่นคือจุดทั้งหมดในระหว่างบรรทัด
  • ทำซ้ำอัลกอริทึมซ้ำไปยังจุดเหล่านี้เพื่อให้แต่ละจุดเป็นค่าเฉลี่ยของสองจุดรอบ ๆ
  • เมื่อดูเหมือนว่าคะแนนจะไม่เคลื่อนไหวอีกต่อไปฉันวาดระหว่างเล็บใด ๆ ที่พวกเขากำลังสัมผัส

ฉันไม่แน่ใจว่าแกนในพิกเซลนั้นโอเคหรือไม่ มันจะใช้พื้นที่มากกว่า 75% ของพื้นที่เสมอมันอาจจะเล็กจริง ๆ

นี่เป็นแอนิเมชั่นที่ดีที่แสดงให้เห็นถึงสิ่งที่ฉันทำอยู่ที่นี่:

ป้อนคำอธิบายรูปภาพที่นี่

ในที่สุดมันก็กลายเป็นสิ่งนี้ซึ่งจุดต่าง ๆ แทบไม่เคลื่อนไหว นี่คือเมื่อฉันเห็นสิ่งที่เล็บสัมผัส:

ป้อนคำอธิบายรูปภาพที่นี่

นี่คือโค้ดอนิเมชั่นที่ไม่เลวร้าย:

import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Q extends JPanel{
    List<Point>points=new ArrayList<Point>();
    List<Point>n=new ArrayList<Point>();
    public Q() throws InterruptedException{
        double[][]rawPoints={{0, 0}, {2, -1}, {3/2, 4/3}, {7/2, 1/3}, {11/2, 16/3}, {1, 16/3}, {0, 1}, {7, -2}, {3, 4}, {8, 1}, {3, -1}, {11, 0}};
        double[][]rawNails={{1, 1}, {3, 1}, {4, 4}, {1, 3}, {2, 2}, {5, -1}, {5, 0}, {6, 2}, {7, 1}, {6, 0}};
        List<Point>p=new ArrayList<Point>(),nails = new ArrayList<Point>();
        double factor = 50;
        for(double[]rawP:rawPoints){p.add(new Point(rawP[0]*factor+100,rawP[1]*factor+100));}
        for(double[]rawN:rawNails){nails.add(new Point(rawN[0]*factor+100,rawN[1]*factor+100));}
        n=nails;
        JFrame frame=new JFrame();
        frame.setSize(700,500);
        frame.setVisible(true);
        frame.getContentPane().add(this);
        d(p,nails);
    }
    public static void main(String[]a) throws InterruptedException{
        new Q();
    }
    void d(List<Point>a,List<Point>nails) throws InterruptedException{
        //add midpoint every iteration until length of 1 is achieved
        //begin algorithm
        //stop points that are within a small amount of a nail
        double distance=20;
        while(distance>1){
            distance=0;
            for (int i=0;i<a.size()-1;i+=2){
                double fir=a.get(i).x;
                double sec=a.get(i).y;
                double c=(fir+a.get(i+1).x)/2;
                double d=(sec+a.get(i+1).y)/2;
                a.add(i+1,new Point(c,d));
                double dist=distBP(new Point(fir,sec),new Point(c,d));
                if(dist>distance){distance=dist;}
            }
        }
        for(Point p:a){a.set(a.indexOf(p), new Point(p.x,p.y));}
        //algorithm starts here:
        setEqual(a);
        repaint();
        invalidate();
        System.out.println(a);
        int count=0;
        while(true){
            count++;
            for(int index=0;index<a.size()-2;index++){
                double x2=(a.get(index).x+a.get(index+2).x)/2;
                double y2=(a.get(index).y+a.get(index+2).y)/2;
                int pointStable=0;
                if(distBP(a.get(index),a.get(index+1))<.5){a.remove(index);}
                for(Point n:nails){
                    if(distBP(n,new Point(x2,y2))<1){pointStable=1;}
                }
                if(pointStable==0){a.set(index+1, new Point(x2,y2));}
            }
            if(count%10==0){
            setEqual(a);
            invalidate();
            repaint();
            Thread.sleep(5);
            }
        }
        //System.out.println(a);
    }
    void setEqual(List<Point>a){
        points = new ArrayList<Point>();
        for(Point p:a){points.add(p);}
    }
    double distBP(Point a,Point b){
        return Math.sqrt(Math.pow(b.x-a.x, 2)+Math.pow(b.y-a.y, 2));
    }
    @Override
    public void paintComponent(Graphics g){
        g.setColor(Color.white);
        g.fillRect(0,0,getWidth(),getHeight());
        g.setColor(Color.black);
        for(Point p:points){
            g.drawRect((int)p.x, (int)p.y, 1, 1);
        }
        for(Point nail:n){
            g.drawOval((int)nail.x-2, (int)nail.y-2, 4, 4);
        }
    }
}

7
ชื่อผู้ใช้ของคุณเหมาะสมกับปัญหานี้
phosgene

Ell ให้กรณีขอบที่น่าสนใจที่ฉันไม่ได้คิด ฉันได้ชี้แจงรายละเอียดและเพิ่มตัวอย่างนั้น โค้ดของคุณทำงานอย่างไรในตัวอย่างนั้น เนื่องจากสิ่งนี้ได้รับการชี้แจงหลังจากโพสต์ของคุณคุณไม่จำเป็นต้องแก้ไขรหัสของคุณหากไม่เป็นไปตามข้อกำหนดที่อัปเดต แต่ฉันคิดว่าฉันจะแจ้งให้คุณทราบ
Martin Ender

ฉันแนะนำการเปลี่ยนแปลงบางอย่างเพื่อแก้ไข แต่ก็พบข้อผิดพลาดในโปรแกรมของฉัน (ถ้าคุณลองใส่มันตัวอย่างสุดท้ายมันจะแสดงเพียงหนึ่งบรรทัด) ฉันจะพยายามแก้ไข
ยืด Maniac
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.