Căng thẳng trên đồ thị, Phần II: Một dải cao su


13

Đây là lần thứ hai trong hai thử thách về "kéo chức năng". Đây là phần I đơn giản hơn một chút .

Hãy lái m đinh vào một bảng ở các vị trí (x 1 , y 1 ) đến (x m , y m ) . Buộc một dải cao su vào đầu tiên và cuối cùng của những cái đó và kéo dài xung quanh các móng khác, sao cho dải băng đi qua tất cả các móng theo thứ tự. Lưu ý rằng dải cao su hiện mô tả chức năng tham số tuyến tính từng phần (x (t), y (t)) trong không gian 2D.

Bây giờ lái xe n đinh khác vào bảng, tại các vị trí (x 1 , y 1 ) đến (x n , y n ) . Nếu bây giờ chúng ta loại bỏ tất cả các móng m ban đầu trừ cái đầu tiên và cái cuối cùng (mà hai đầu của cao su được buộc vào), dây cao su sẽ rút ngắn cho đến khi nó nằm căng xung quanh móng mới, mang lại một chức năng tuyến tính khác.

Ví dụ: lấy m = 12 móng ban đầu tại các vị trí (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 móng nữa tại các vị trí (1, 1), (3, 1), (4, 4), (1, 3), (2, 2), (5, -1), (5, 0 ), (6, 2), (7, 1), (6, 0) . Ba lô sau đây cho thấy quá trình được mô tả ở trên:

nhập mô tả hình ảnh ở đây

Đối với phiên bản lớn hơn: Nhấp chuột phải -> Mở trong tab mới

Và đây là hình ảnh động của dây cao su thắt chặt nếu bạn gặp khó khăn khi hình dung nó:

nhập mô tả hình ảnh ở đây

Các thách thức

Đưa ra hai danh sách "đinh", vẽ dây cao su taut xung quanh danh sách thứ hai nếu nó bắt đầu từ hình dạng đi qua tất cả các móng trong danh sách đầu tiên.

Bạn có thể viết chương trình hoặc hàm và nhận đầu vào thông qua STDIN, ARGV hoặc đối số hàm. Bạn có thể hiển thị kết quả trên màn hình hoặc lưu hình ảnh vào một tệp.

Nếu kết quả được rasterized, nó cần tối thiểu 300 pixel cho mỗi bên. Dải cao su và đinh cuối cùng phải bao phủ ít nhất 75% phạm vi ngang và dọc của hình ảnh. Thang đo chiều dài của xy phải giống nhau. Bạn cần hiển thị móng trong bộ thứ hai (sử dụng ít nhất 3x3 pixel) và chuỗi (rộng ít nhất 1 pixel). Bạn có thể hoặc không bao gồm các trục.

Màu sắc là lựa chọn của bạn, nhưng bạn cần ít nhất hai màu có thể phân biệt: một cho nền và một cho móng và chuỗi (những màu này có thể có màu khác nhau).

Bạn có thể cho rằng tất cả các đinh trong danh sách thứ hai đều cách xa hình dạng ban đầu của dây cao su ít nhất 10 -5 đơn vị (do đó bạn không cần phải lo lắng về sự thiếu chính xác của dấu phẩy động).

Đây là mã golf, vì vậy câu trả lời ngắn nhất (tính bằng byte) sẽ thắng.

Thêm ví dụ

Dưới đây là hai ví dụ khác:

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

nhập mô tả hình ảnh ở đây

{{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}}

nhập mô tả hình ảnh ở đây

Và đây là một ví dụ cho thấy tầm quan trọng của hai trong số những chiếc đinh ban đầu còn lại. Kết quả sẽ được bkhông một :

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

nhập mô tả hình ảnh ở đây

Cảm ơn Ell đã cung cấp ví dụ này.


@laurencevs Chuỗi một là giá trị đơn, giúp đơn giản hóa đáng kể mọi thứ, bởi vì có một hướng rõ ràng để xử lý chức năng và móng. Cái này có thể chứa các vòng lặp và zigzags, và hình thức của hàm là khác nhau đáng kể (và biến), có nghĩa là các giải pháp nên khác nhau đáng kể.
Martin Ender

Đầu ra của cái này là gì?
Ell

@Ell Ah, trường hợp thử nghiệm rất tốt đẹp. Tôi cho rằng để thống nhất, nó phải là b , nhưng tôi thực sự cần phải làm rõ câu hỏi về điều đó. Sẽ làm điều đó sớm thôi. Cảm ơn!
Martin Ender

Câu trả lời:


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()

Đọc hai danh sách các điểm từ STDIN.

Thí dụ

[(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)]

Hình 1

Làm thế nào nó hoạt động

Chìa khóa cho giải pháp là làm việc theo các bước nhỏ, tăng dần. Thay vì cố gắng tìm hiểu điều gì xảy ra khi chúng ta loại bỏ tất cả các móng tay cùng một lúc, chúng tôi tập trung vào các tác động trực tiếp của việc loại bỏ chỉ một móng tay. Sau đó chúng ta có thể loại bỏ từng cái đinh theo thứ tự tùy ý.

Làm việc tăng dần có nghĩa là chúng ta phải theo dõi trạng thái trung gian của dây cao su. Đây là phần khó khăn: chỉ theo dõi những chiếc đinh mà ban nhạc chạy qua là không đủ. Trong quá trình tháo móng, ban nhạc có thể bị thương và sau đó tháo ra xung quanh móng. Do đó, khi ban nhạc tương tác với một chiếc đinh, chúng ta phải theo dõi bao nhiêu lần và theo hướng nó quấn quanh nó. Chúng tôi làm điều đó bằng cách gán một giá trị cho mỗi móng dọc theo dải như vậy:

Hình 2

Lưu ý rằng:

  • Chúng tôi bắt đầu đếm ngay khi ban nhạc tiếp xúc với móng, mặc dù móng không ảnh hưởng nghiêm trọng đến hình dạng của nó. Hãy nhớ lại rằng, không giống như hình minh họa, móng tay của chúng ta là không thứ nguyên. Do đó, nếu ban nhạc trở nên tiếp xúc với móng tay, chúng ta không thể biết được phía nào của ban nhạc chỉ ở vị trí của nó --- chúng ta phải theo dõi nơi mà nó từng có liên quan đến ban nhạc.

  • Chúng tôi giữ xung quanh móng tay với giá trị bằng 0, nghĩa là móng đã từng, nhưng không còn giữ băng, thay vì loại bỏ chúng ngay lập tức. Nếu chúng ta làm như vậy, nó có thể gây ra phản ứng dây chuyền không mong muốn, trong khi chúng ta đang cố gắng giữ hiệu ứng của từng bước được bản địa hóa. Thay vào đó, móng tay có giá trị bằng 0 được coi là đủ điều kiện để loại bỏ như là một phần của quy trình lớn hơn.

Bây giờ chúng ta có thể mô tả những gì xảy ra ở mỗi bước:

  • Chúng tôi chọn một cái đinh để loại bỏ khỏi đường dẫn hiện tại của ban nhạc. Một móng tay đủ điều kiện để loại bỏ nếu đó là một phần của bộ móng đầu tiên (lưu cho các điểm cuối) hoặc nếu giá trị của nó bằng không.

  • Giả vờ rằng hai móng lân cận đã được cố định, chúng tôi tìm ra móng nào từ bộ thứ hai hoặc cặp điểm cuối mà ban nhạc sẽ chạy qua khi móng được chọn bị loại bỏ (chúng tôi không bận tâm với phần còn lại của móng từ đầu tiên được thiết lập, vì họ sẽ cuối cùng tất cả được gỡ bỏ.) Chúng tôi làm điều đó trong một thời trang tương tự như giải pháp cho Phần I . Tất cả các đinh này ở cùng một phía của ban nhạc, do đó chúng tôi gán cho tất cả chúng một giá trị là 1 hoặc -1 , tùy thuộc vào bên.

  • Chúng tôi cập nhật giá trị của hai móng tay lân cận để phản ánh các thay đổi đối với đường dẫn của ban nhạc (dễ dàng là phần khó nhất!)

Quá trình này được lặp lại cho đến khi không còn móng nào để loại bỏ:

Hình 3

Và đây là một ví dụ phức tạp hơn minh họa cho ban nhạc quấn quanh móng tay nhiều lần:

hinh 4


Kinh ngạc! Chỉ có một điều: những đồ họa đó được rasterized hoặc chúng là đồ họa vector? Trong trường hợp trước, tôi sẽ phải chỉ cho bạn "Tỷ lệ chiều dài của x và y phải giống nhau." Ngoài ra, bạn đang sử dụng cái gì để tạo ra tất cả những đồ họa bạn sử dụng trong phần giải thích của mình. matplotlib, quá?
Martin Ender

Cảm ơn! Ơ ... Vì matplotlib hãy để tôi mở rộng cốt truyện khi tôi sẽ đi với đồ họa vector :) Đối với các minh họa tôi sử dụng chủ yếu là GeoGebra . Đó là một chút kỳ quặc nhưng nó hoàn thành công việc.
Ell

Vâng, nếu bạn có thể thay đổi kích thước tùy ý, điều đó tốt. Cảm ơn liên kết, tôi sẽ kiểm tra xem!
Martin Ender

4

Java - 1262 byte

Tôi biết điều này có lẽ không được chơi golf nhiều như nó có thể.

Tuy nhiên, không ai khác dường như đang bước lên tấm và trả lời câu hỏi này, vì vậy tôi sẽ.

Đầu tiên, lớp "T" - là lớp điểm - 57 byte

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

Và lớp chính - 1205 byte

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);}}}}

Thí dụ:

nhập mô tả hình ảnh ở đây

Để chạy, hãy gọi hàm "d" với Danh sách các điểm và một mảng đinh (vâng, tôi biết, kỳ lạ). Những gì nó làm:

  • tạo một danh sách các điểm đại diện cho các dòng - nghĩa là tất cả các điểm ở giữa các dòng.
  • lặp lại một thuật toán lặp đi lặp lại các điểm này sao cho mỗi điểm là trung bình của hai điểm xung quanh nó.
  • Khi các điểm dường như không di chuyển nhiều nữa, tôi vẽ giữa bất kỳ móng nào mà chúng chạm vào.

Tôi không chắc chắn nếu trục trong pixel là ok. Nó sẽ luôn chiếm hơn 75% không gian, nó có thể thực sự rất nhỏ.

Đây là một hình ảnh động đẹp để chứng minh những gì tôi đang làm ở đây:

nhập mô tả hình ảnh ở đây

Cuối cùng, nó trở thành thế này, trong đó các điểm hầu như không di chuyển. Đây là khi tôi thấy những gì móng tay nó chạm vào:

nhập mô tả hình ảnh ở đây

Đây là mã không hoạt động, mã hoạt hình:

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
Tên người dùng của bạn rất phù hợp với vấn đề này.
phosgene

Ell đã cung cấp một trường hợp cạnh thú vị mà tôi không nghĩ về. Tôi đã làm rõ thông số kỹ thuật và thêm ví dụ đó. Làm thế nào để mã của bạn thực hiện trên ví dụ đó? Vì điều này đã được làm rõ sau bài đăng của bạn, bạn không bắt buộc phải sửa mã của mình, nếu nó không tuân thủ thông số kỹ thuật được cập nhật, nhưng tôi nghĩ tôi sẽ cho bạn biết.
Martin Ender

Tôi đã giới thiệu một số thay đổi để sửa nó, nhưng nó đã tiết lộ một lỗi trong chương trình của tôi (nếu bạn cố gắng nhập nó vào ví dụ cuối cùng, nó chỉ hiển thị một dòng). Tôi sẽ cố gắng sửa nó.
Căng thẳng điên cuồng
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.