Q: In an x-y coordinate system (or Cartesian coordinate system), how many paths are there from the point of origin to a point with coordinates ⟨x, y⟩, where
- x ∧ y ∈ Z + (x and y are positive integers),
- a path is built up from exactly x + y segments, each with a length of one (1), and
- a line segment must be either horizontal or vertical?
See below for answer.
A: When visualizing the path, we can imagine a cursor, drawing the path starting from ⟨0, 0⟩, moving to ⟨x, y⟩ in x + y discrete steps.
This movement forms an n-length list of segments, where n = x + y.
L = ⟨s1, s2, … sn⟩ n = x + y
A segment can either be horizontal (h), or vertical (v). To reach from the point of origin to ⟨x, y⟩ we need to move the cursor x units to the right (horizontally), and y units up (vertically). This gives us the following set of segments, which corresponds to the list L,
S = {h1, h2, … hx, v1, v2, … vy},
where hn represents a horizontal segment, and vn a vertical.
One way of getting all the possible paths is to list all the permutations of the set S. The number of permutations of an n-element set is n! (n factorial). The problem with this approach, however, is that it gives us several identical paths. Consider the three lists,
- ⟨h1, h2, h3, v1, v2⟩,
- ⟨h1, h3, h2, v1, v2⟩, and
- ⟨h1, h3, h2, v2, v1⟩.
These are all identical as paths. In fact, all h-segments should be considered equivalent, and so should v-segments. Therefore, to get the number of unique lists, we need to divide our result up into equivalence classes, and then count the number of these.
Since there are x number of h-segments, there are x! lists in each class of lists that should be considered equivalent with respect to their h-segments. Similarly, there are y! list arrangements that correspond to the same y-element set.
Dividing the number of S permutations (x + y)! by x! × y! therefore gives us the number of unique paths from ⟨0, 0⟩ to ⟨x, y⟩.
This is also known as the binomial coefficient. We use the familiar n choose k-notation to express this as:
The number of paths from ⟨0, 0⟩ to ⟨x, y⟩ is therefore:
Example:
Take x = 4, and y = 3.This gives us,
S = {h1, h2, h3, h4, v1, v2, v3},
and n = 7.
By selecting the various elements of S, and putting them in a list, we get the (x + y)! number of permutations of S:
This gives us 7 × 6 × 5 × 4 × 3 × 2 × 1 (= 5040) lists. To partition this set of lists into groups, each containing all the lists we consider equivalent, we recollect that an x-element set has x! permutations:
This gives us 7! / (4! × 3!) = 35 paths.
The following is a C++ program that draws the paths from the origin to a point ⟨x, y⟩. It uses the Qt library:
cartpathwidget.h:
#ifndef CARTPATHWIDGET_H #define CARTPATHWIDGET_H #include <QWidget> #include <vector> class QSlider; class QEvent; class CartPathWidget : public QWidget { Q_OBJECT public: CartPathWidget(int x, int y, QWidget *parent = 0); ~CartPathWidget() {} void rebuild(); protected slots: void setX(int x); void setY(int y); protected: bool eventFilter(QObject *object, QEvent *event); private: void build(int n, int x = 1); int m_x; int m_y; std::vector<bool> m_e; std::vector<std::vector<bool> > m_result; QSlider *const m_slider; }; #endif // CARTPATHWIDGET_Hmainwindow.h:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QtGui/QMainWindow> class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); }; #endif // MAINWINDOW_Hcartpathwidget.cpp:
#include <QSpinBox> #include <QSlider> #include <QEvent> #include <QHBoxLayout> #include <QPainter> #include "cartpathwidget.h" CartPathWidget::CartPathWidget(int x, int y, QWidget *parent) : QWidget(parent), m_x(x), m_y(y), m_slider(new QSlider(Qt::Vertical)) { rebuild(); QWidget *w = new QWidget; QHBoxLayout *layout = new QHBoxLayout; QVBoxLayout *vlayout = new QVBoxLayout; vlayout->addLayout(layout); QHBoxLayout *hlayout = new QHBoxLayout; vlayout->addLayout(hlayout); setLayout(vlayout); layout->addWidget(w); layout->addWidget(m_slider); w->installEventFilter(this); QSpinBox *sb1 = new QSpinBox; sb1->setRange(1, 9); sb1->setValue(m_x); hlayout->addWidget(sb1); QSpinBox *sb2 = new QSpinBox; sb2->setRange(1, 9); sb2->setValue(m_y); hlayout->addWidget(sb2); connect(m_slider, SIGNAL(valueChanged(int)), w, SLOT(update())); connect(sb1, SIGNAL(valueChanged(int)), this, SLOT(setX(int))); connect(sb2, SIGNAL(valueChanged(int)), this, SLOT(setY(int))); } void CartPathWidget::setX(int x) { if (m_x != x) { m_x = x; rebuild(); } } void CartPathWidget::setY(int y) { if (m_y != y) { m_y = y; rebuild(); } } void CartPathWidget::rebuild() { m_result.clear(); m_e.clear(); for (int i = 0; i < m_x + m_y; ++i) m_e.push_back(false); build(m_y + 2); m_slider->setRangesetValue(0); update(); } bool CartPathWidget::eventFilter(QObject *object, QEvent *event) { if (QEvent::Paint == event->type()) { QWidget *w = qobject_cast<QWidget *>(object); if (!w) return QWidget::eventFilter(object, event); QPainter painter(w); QTransform t; t.translate(w->width() / 4, w->height() / 4); t.scale(w->width() / (m_x * 2), w->height() / (m_y * 2)); painter.setTransform(t); // Draw grid for (int x = 0; x <= m_x; ++x) { painter.drawLine(x, 0, x, m_y); } for (int y = 0; y <= m_y; ++y) { painter.drawLine(0, y, m_x, y); } // Draw path const std::vector<bool> &path = m_result[m_slider->value()]; int x = 0; int y = 0; QPen pen; pen.setColor(Qt::red); pen.setWidthF(0.15); painter.setPen(pen); std::vector<bool>::const_iterator i; QPolygonF p; p.push_back(QPointF(m_x, 0)); for (i = path.begin(); i != path.end(); ++i) { (*i ? x : y) += 1; p.push_back(QPointF(m_x - x, y)); } painter.drawPolyline(p); } return QWidget::eventFilter(object, event); } void CartPathWidget::build(int n, int x) { int e = n - (m_y + 1); for (int c = x; c < n; ++c) { m_e[c - 1] = true; (e < m_x) ? build(n + 1, c + 1) : m_result.push_back(m_e); m_e[c - 1] = false; } }main.cpp:
#include <QtGui/QApplication> #include "mainwindow.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }mainwindow.cpp:
#include "mainwindow.h" #include "cartpathwidget.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { setCentralWidget(new CartPathWidget(3, 2)); } MainWindow::~MainWindow() { }paths.pro:
QT += core gui TARGET = paths TEMPLATE = app SOURCES += main.cpp\ mainwindow.cpp \ cartpathwidget.cpp HEADERS += mainwindow.h \ cartpathwidget.h
0 comments:
Post a Comment