9. GRAPH ALGORITHMS.

Slides:



Advertisements
งานนำเสนอที่คล้ายกัน
Another one of Data Structure
Advertisements

รายวิชา ง40206 โครงสร้างข้อมูลและขั้นตอนวิธี
Stack.
คืออะไร? คือ queue ที่ access element ตามความสำคัญของตัว element นั้น
สมชาย ประสิทธิ์จูตระกูล
แถวคอย (Queue).
Data structure & Algorithms
Asst.Prof. Dr.Surasak Mungsing
Asst.Prof. Dr.Surasak Mungsing
CSC201 Analysis and Design of Algorithms Greedy, Divide and Conquer
Asst.Prof. Dr.Surasak Mungsing
ให้ประหยัดการใช้หน่วยความจำ (space) ด้วยความรวดเร็ว (time)
คิว (Queue) Queue ADT Queue เป็น List ชนิดหนึ่ง แต่สำหรับ queue การแทรกข้อมูลลงบน queue (Insertion) จะทำที่ปลายใดปลายหนึ่งของ Queue ในขณะที่การลบข้อมูลออกจากคิว.
วิชา COSC2202 โครงสร้างข้อมูล (Data Structure)
หลักสูตรอบรมครู คอมพิวเตอร์ หลักสูตรอบรมครู คอมพิวเตอร์ หลักสูตรที่ ๑ ทักษะการโปรแกรม เบื้องต้น วันที่สาม.
คำสั่งแบบมีเงื่อนไข Conditional Statements
Shortest-Path Algorithms
PERT/CPM.
Discrete Math Lecture 10: Graphs
การกำหนดโครงการ (Project Scheduling: PERT / CPM)
กราฟเบื้องต้น.
WATTANAPONG SUTTAPAK SOFTWARE ENGINEERING, SCHOOL OF INFORMATION COMMUNICATION TECHNOLOGY, UNIVERSITY OF PHAYAO Chapter 9 Heap and Hash 1.
กราฟเบื้องต้น.
WATTANAPONG SUTTAPAK SOFTWARE ENGINEERING, SCHOOL OF INFORMATION COMMUNICATION TECHNOLOGY, UNIVERSITY OF PHAYAO Chapter 6 Graph 1.
หน่วยที่ 6 กราฟ (Graphs)
Trees Hierarchical Structures. Outlines Definition of trees Modeling by trees Properties of trees Applications – Binary search trees – Prefix codes –
Collections. Data structures Data Structures ( โครงสร้างข้อมูล ) เกิดจากการ นำข้อมูลขั้นพื้นฐานที่แบ่งแยกไม่ได้ (atomic data type) เช่น int, char, double.
QueueQueue Lecturer : Kritawan Siriboon, Room no. 913 Text : Data Structures & Algorithm Analysis in C, C++,… Mark Allen Weiss, Addison Wesley.
Linked List ( ต่อ ) Lecturer : Kritawan Siriboon, Room no. 913 Text : Data Structures & Algorithm Analysis in C, C++,… Mark Allen Weiss, Addison Wesley.
Queue Lecturer : Kritawan Siriboon, Room no. 913
ACM ICPC Training Nattee Niparnan.
Chapter 8: Single-Area OSPF
List, Stack, Queue 2018/9/21.
การบริหารโครงการด้วย PERT & CPM
การประมวลผลแบบวน ( LOOP )
การทดสอบซอฟต์แวร์ Software Testing
บทที่ 12 กราฟ (Graph).
Linked List.
บทที่ 6 การกำหนดเวลางานโครงการ
บทที่ 14 กลวิธีการทดสอบซอฟต์แวร์ (TESTING STRATEGIES)
INC 161 , CPE 100 Computer Programming
Data Structure & Algorithm Concept
Linked List.
Graph Lecturer : Kritawan Siriboon, Boontee Kruatrachue Room no. 913
การวิเคราะห์และออกแบบขั้นตอนวิธี
Graph Lecturer : Kritawan Siriboon, Boontee Kruatrachue Room no. 913
Graph Lecturer : Kritawan Siriboon, Boontee Kruatrachue Room no. 913
13 October 2007
Graph Lecturer : Kritawan Siriboon, Boontee Kruatrachue Room no. 913
Dr.Surasak Mungsing CSE 221/ICT221 การวิเคราะห์และออกแบบขั้นตอนวิธี Lecture 13: การคำนวณได้และการตัดสินใจของปัญหา ที่ยากต่อการแก้ไข.
DEADLOCKS Advanced Operating System Operating System Technology
Linked List Lecturer : Kritawan Siriboon, Room no. 913
Asst.Prof. Dr.Surasak Mungsing
Rewrite by Burin Rujjanapan Updated:
Data Structure and Algorithm
Dr.Surasak Mungsing CSE 221/ICT221 Analysis and Design of Algorithms Lecture 04: Time complexity analysis in form of Big-Oh.
Dr.Surasak Mungsing CSE 221/ICT221 การวิเคราะห์และออกแบบขั้นตอนวิธี Lecture 04: การวิเคราะห์หาความซับซ้อนด้านเวลา ในรูป.
2. Algorithm Analysis.
Linked List (ต่อ) Lecturer : Kritawan Siriboon, Room no. 913
Dr.Surasak Mungsing CSE 221/ICT221 การวิเคราะห์และออกแบบขั้นตอนวิธี Lecture 11: เทคนิคการออกแบบขั้นตอนวิธีตอนวิธี Greedy,
Dr.Surasak Mungsing CSE 221/ICT221 การวิเคราะห์และออกแบบขั้นตอนวิธี Lecture 05: การวิเคราะห์ความซับซ้อนของ ขั้นตอนวิธีการเรียงลำดับข้อมูล.
Data Structures & Algorithms Using Python
Algorithms Analysis Sanchai Yeewiyom
บทที่ 7 การวิเคราะห์โครงข่ายงาน PERT/CPM
Data Structures and Algorithms 2/2561
การวิเคราะห์และออกแบบขั้นตอนวิธี
4.4 AVL Trees AVL (Adelson-Velskii and Landis) tree เป็น binary search tree กำกับด้วยเงื่อนไขของการสมดุล และประกันว่า depth ของ tree จะเป็น O(log n) อย่างง่ายที่สุดคือกำหนดว่า.
4.7. B-Trees โครงสร้าง tree ที่กล่าวถึงมาแล้วนั้น อยู่บนสมมติฐานที่ว่าโครงสร้างทั้งหมดสามารถจัดเก็บอยู่ในหน่วยความจำของเครื่องคอมพิวเตอร์ได้ ถ้า จำนวนข้อมูลมีปริมาณมากเกินกว่าที่จะเก็บไว้ใน.
การวิเคราะห์และออกแบบขั้นตอนวิธี
Dr.Surasak Mungsing CSE 221/ICT221 การวิเคราะห์และออกแบบขั้นตอนวิธี Lecture 12: เทคนิคการออกแบบขั้นตอนวิธีตอนวิธี Dynamic.
ใบสำเนางานนำเสนอ:

9. GRAPH ALGORITHMS

ในบทนี้จะกล่าวถึงปัญหาทั่วไปของทฤษฎีกราฟ กล่าวถึงปัญหาที่สามารถใช้ทฤษฎีกราฟเพื่อแก้ไขได้ กล่าวถึงอัลกอริทึมในการแก้ปัญหากราฟ แสดงให้เห็นว่าการเลือกโครงสร้างข้อมูลที่เหมาะสมจะลด running time ของอัลกอริทึมดังกล่าวนั้นได้มาก แสดงกรรมวิธีที่สำคัญที่เรียกว่า depth-first search ในการแก้ปัญหา

9.1 นิยาม Graph G = (V, E) ประกอบด้วยเซ็ตของ vertices, V, และเซ็ตของ edges, E แต่ละ edge คือคู่ของ (v,w), เมื่อ v,w  V บางครั้งก็เรียก Edges ว่า arcs ถ้า edge เป็นคู่อันดับก็จะได้กราฟเป็นแบบ directed graph Directed graphs เรียกสั้น ๆ ว่า digraphs Vertex w เป็น adjacent กับ v ถ้า (iff) (v,w)  E สำหรับ undirected graph ที่มี edge (v,w) นั่นคือมี (w,v), ดังนั้น w เป็น adjacent กับ v และ v เป็น adjacent กับ w

บางครั้ง edge อาจจะมีองค์ประกอบที่เรียกว่า weight หรือ cost path ในกราฟ คือลำดับของ vertices w1, w2, w3, . . . , wn ที่ (wi, wi+i)  E สำหรับ 1  i < n length ของ path คือ จำนวน edges บน path ซึ่งเท่ากับ n – 1 กรณีที่กราฟมี edge (v,v) จาก vertex ไปยังตัวมันเองแล้ว เรียก path v, v ว่า loop กราฟที่เราจะศึกษากันโดยทั่วไปแล้วไม่มี loop simple path คือ path ที่มี vertices ทั้งหมดไม่ซ้ำกัน ยกเว้นตัวแรกและตัวสุดท้ายอาจเป็นตัวเดียวกันได้

cycle ใน directed graph คือ path ที่มี length อย่างน้อยเท่ากับ 1 ซึ่งมี w1 = wn; และ cycle นี้เรียกว่า simple cycle ถ้า path เป็น simple path สำหรับ undirected graphs แล้วกรณีนี้ต้องเป็นคนละ edge กัน directed graph เป็น acyclic ถ้าไม่มี cycles และ เขียนย่อ ด้วยคำว่า DAG

undirected graph เป็นแบบ connected ถ้ามี path หนึ่งจากทุก ๆ vertex ไปยัง vertex อื่น ๆ สำหรับ directed graph ที่มีคุณสมบัติดังกล่าวนี้ จะเรียกว่า strongly connected. ถ้า directed graph ไม่เป็น strongly connected แต่ถ้ายกเลิกทิศทางเสียแล้วทำให้มันเป็น connected ได้ ก็จะเรียกกราฟนี้ว่า weakly connected complete graph คือ graph ที่มี edge (หนึ่ง edge) ระหว่าง vertices ทุกคู่

ระบบเส้นทางการบินเป็นตัวอย่างหนึ่งที่จำลองแบบได้ด้วย graph สนามบินแต่ละแห่งแทนได้ด้วย vertex หนึ่ง และ vertices 2 vertices เชื่อมต่อด้วย edge หนึ่งถ้าเป็นการบินตรงระหว่างสนามบินทั้งสอง แต่ละ edge อาจประกอบด้วย weight ซึ่งอาจจะหมายถึงเวลาที่ใช้ในการบิน หรือระยะทาง หรือค่าตั๋วก็ได้ การจราจรก็สามารถจำลองได้ด้วย graph จุดตัดของถนนแทนได้ด้วย vertex หนึ่ง และถนนแต่ละเส้นก็คือ edge โดยที่ edge costs อาจหมายถึงขีดจำกัดความเร็ว หรือจำนวนเลนวิ่งก็ได้

9.1.1. Representation of Graphs ในที่นี้จะกล่าวถึง directed graphs (ส่วน undirected graphs ก็มีลักษณะคล้ายกัน) สมมุติให้เราสามารถกำหนดหมายเลขให้แก่ vertices ได้ โดยเริ่มจาก 1 กราฟในรูป Figure 9.1 มี 7 vertices 12 edges วิธีอย่างง่ายในการจำลอง graph คือการใช้ two-dimensional array ซึ่งเรียกว่า adjacency matrix representation ดังนี้ สำหรับแต่ละ edge (u, v), กำหนดให้ a[u][v] เป็น true; ถ้าไม่มี edge ก็ให้เป็น false กรณีที่มี weight ด้วยก็กำหนดให้ a[u][v] มีค่าเท่ากับ weight และให้ใช้ค่า weight สูงมาก ๆ หรือ ต่ำมาก ๆ เป็น sentinel ที่หมายถึงไม่ edges อยู่

9.1.1. Representation of Graphs 2 6 4 5 3 7 Figure 9.1 Directed graph การใช้ adjacency matrix ดูจะง่ายแต่ต้องใช้เนื้อที่  (|V|2), ใช้กับ กราฟนั้นมี edges จำนวนมาก dense graph กล่าวคือ |E| =  (|V|2)

9.1.1. Representation of Graphs ถ้าไม่เป็น dense graph (เรียกว่า graph แบบ sparse) ก็จะใช้ adjacency list แทน คือ แต่ละ vertex มี list ของ adjacent vertices ทั้งหมดของมัน และใช้เนื้อที่ขนาด O(|E| + |V|) จากรูป Figure 9.2 โครงสร้างทางด้านซ้ายเป็นเพียง array ที่มี header เท่านั้น กรณีที่ edges มี weights ด้วย ก็เพียงเพิ่มเติมข้อมูลนี้ลงใน cells ด้วยเท่านั้น

9.1.1. Representation of Graphs Adjacency lists เป็นวิธีมาตรฐานที่ใช่ในการแทน graphs สำหรับ Undirected graphs แล้ว แต่ละ edge (u, v) จะปรากฏอยู่ใน lists สองแห่ง การทำงานพื้นฐานที่ต้องใช้ในอัลกอริทึมของกราฟ คือ การหา vertices ที่ adjacent กับ vertex v ที่กำหนด และสามารถทำได้โดยใช้เวลาที่ผกผันตามจำนวน vertices ที่พบด้วยการใช้การ scan ไปตาม adjacency list

1 2 3 4 5 6 - 7 0 1 1 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0 1 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 2 4 5 - 6 7 3 4 3 - 6 - 6 Figure 9.2 An adjacency list and adjacency matrix representation of a graph

9.2. Topological Sort topological sort คือลำดับของ vertices ใน directed acyclic graph ที่ถ้ามี path หนึ่งจาก vi ไปยัง vj, แล้ว vj มีลำดับที่ตามหลัง vi กราฟในรูป Figure 9.3 ใช้แทนโครงสร้างความต่อเนื่องของรายวิชาtopological ordering ของรายวิชาคือลำดับรายวิชาที่เป็นไปตามข้อกำหนดเงื่อนไขรายวิชา (prerequisite)

ยิ่งกว่านั้น ordering ไม่จำเป็นต้องเป็น unique แน่นอนว่า topological ordering เป็นไปไม่ได้สำหรับกราฟที่มี cycle เนื่องจาก vertices v และ w ในเส้นทาง cycle นั้นมี v ก่อน w และมี w ก่อน v ยิ่งกว่านั้น ordering ไม่จำเป็นต้องเป็น unique กราฟรูป Figure 9.4, มี v1, v2, v5, v4, v3, v7, v6 และมี v1, v2, v5, v4, v7, v3, v6 ทั้งสองเป็น topological orderings v1 v2 v6 v4 v5 v3 v7

อัลกอริทึมอย่างง่ายในการหา topological ordering คือ ตอนแรกหา vertex ที่ไม่มี incoming edges เป็นจุดเริ่มต้น แล้วพิมพ์ชื่อ vertex นี้พร้อมกับย้ายมันพร้อมกับ edges ออกจากกราฟ จากนั้นก็ทำเช่นเดียวกันนี้กับส่วนที่เหลือในกราฟ กำหนดให้ indegree ของ vertex v คือจำนวนของ edges (u,v) เราคำนวณค่า indegrees ของ vertices ทั้งหมดในกราฟได้ โดยถ้ามี indegree array และกราฟนั้นถูกจัดอยู่ใน adjacency list แล้ว เราก็สามารถใช้อัลกอริทึมใน Figure 9.5 เพื่อสร้าง topological ordering ได้

Figure 9.5 Simple topological sort pseudocode void topsort() throws CycleFound { vertex v, w; for ( int counter=0; counter<NUM_VERTEX; counter++ ) v = findNewVertexOfIndegreeZero( ); if ( v == null ) throw new CycleFound(); v.topNum = counter; for each w adjacent to v w.indegree--; }

findNewVertexOfIndegreeZero เป็นเพียงการ scan ใน indegree array การทำงานแต่ละครั้งใช้เวลา O(|V|) และเนื่องจากมีการเรียกใช้เป็นจำนวน |V| ครั้ง ดังนั้นมันจึงมี running time เป็น O(|V|2) สาเหตุที่มี running time ไม่ดีก็เนื่องจากการ sequential scan ใน indegree array นั่นเอง เราสามารถปรับปรุงประสิทธิภาพได้ด้วยการนำ (unassigned) vertices ทั้งหมดที่มี indegree เป็น 0 ไปไว้ในกล่องต่างหาก findNewVertexOfIndegreeZero จะให้ค่าเป็น (และย้ายออก) vertex จากกล่องดังกล่าว ขณะที่เราลดค่า indegrees ของ adjacent vertices นั้นเราจะตรวจค่าของมันและย้ายมันไปไว้ในกล่องดังกล่าวเมื่อค่า indegree ของมันลดลงเป็น 0

กล่องดังกล่าวข้างบนนั้น อาจจะใช้ stack หรือ queue ก็ได้ เริ่มต้นด้วยการคำนวณค่า indegree ของทุก ๆ vertex จากนั้น นำ vertices ที่มี indegree เป็น 0 ทั้งหมดไปไว้ใน queue ซึ่งเริ่มต้นเป็น queue ว่าง ให้ทำการย้าย vertex v ออกตราบเท่าที่ queue ยังไม่เป็น queue ว่าง และให้ลดค่า indegrees ของ vextex ทุกตัวที่เป็น adjacent กับ v นำ vertex ไปเข้า queue เมื่อ indegree ของมันเป็น 0 topological ordering ที่ได้ก็คือลำดับที่ vertices ถูก dequeue รูปที่ Figure 9.6 แสดงสถานะการทำงาน

pseudocode ของอัลกอริทึมแสดงในรูปที่ Figure 9.7. 9.2. Topological Sort pseudocode ของอัลกอริทึมแสดงในรูปที่ Figure 9.7. สมมุติให้มี adjacency list และค่า indegrees ของ vertices เรียบร้อยแล้ว ให้ vertex มีข้อมูลชื่อ topNum ซึ่งเป็น topological number ของมัน เวลาที่ใช้ในการทำงานของอัลกอริทึมคือ O(|E| + |V|) ถ้าใช้ adjacency lists ซึ่งจะเห็นได้จาก for loop ที่บรรทัดที่ 8 ที่มีการทำงานเพียงหนึ่งครั้งต่อหนึ่ง edge การทำงานของ queue เกิดขึ้นหนึ่งครั้งต่อหนึ่ง vertex, และการ initialization ก็ใช้เวลาตามขนาดของกราฟเช่นเดียวกัน

Figure 9.6 topological sort ของกราฟรูปFigure 9.4 Indegree before dequeue vertex 1 2 3 4 5 6 7 V1 V2 V3 V4 V5 V6 V7 enqueue v1 v2 v5 v4 v3 v7 v6 dequeue Figure 9.6 topological sort ของกราฟรูปFigure 9.4

Figure 9.7 Pseudocode ของ topological sort void topSort( ) throws CycleFound { Queue q; int counter; vertex v, w; /*1*/ q = new Queue( ); /*2*/ for each vertex v /*3*/ if ( v.indegree == 0 ) /*4*/ q.enqueue( v ); /*5*/ while ( !q.isEmpty() ) { /*6*/ v = q.dequeue( ); /*7*/ v.topNum = ++counter; /* assign next number */ /*8*/ for each w adjacent to v /*9*/ if ( --w.indegree == 0 ) /*10*/ q.enqueue( w ); } /*11*/ if ( counter != NUM_VERTICES ) /*12*/ throw new CycleFound(); } Size of graph At most one per vertex Execute at most once per edge

9.3. Shortest-Path Algorithms Input เป็น weighted graph: คือ edge (vi, vj) มี cost ci,j ในการท่องไปใน edge cost ของ path v1v2 ... vn คือ 𝑖=1 𝑛−1 𝑐 𝑖,𝑖+1 เรียกว่า weighted path length unweighted path length ก็คือ จำนวน edges บนเส้นทางของ path v1v2 ... vn คือ n – 1

SINGLE-SOURCE SHORTEST-PATH PROBLEM: input เป็น weighted graph, G = (V, E), และมี vertex s ให้ทำการหา shortest weighted path จาก s ไปยัง vertex อื่น ๆ ทุก vertex ใน G

v1 v2 v6 v4 v5 v3 v7 6 10 1 8 5 4 2 3 Figure 9.8 directed graph G เช่น กราฟในรูป Figure 9.8, มี shortest weighted path จาก v1 ถึง v6 มี cost เป็น 6 ตามเส้นทางจาก v1 ไป v4 ไป v7 ไปv6 และมี shortest unweighted path เป็น 2

Figure 9.9 graph ที่มี negative-cost cycle 6 -10 1 2 4 5 3 Figure 9.9 graph ที่มี negative-cost cycle

9.3. Shortest-Path Algorithms รูป Figure 9.9 แสดงปัญหาที่เกิดจาก negative edges path จาก v5 ไป v4 มี cost 1 แต่มี path ที่สั้นกว่าคือตาม loop v5, v4, v2, v5, v4 ซึ่งมี cost -5 ความจริงนี่ยังไม่ใช่เส้นทางที่สั้นที่สุดเนื่องจากเราสามารถวนรอบไปได้เรื่อย ๆ นั่นเอง และทำนองเดียวกับ shortest path จาก v1 ไป v6 เนื่องจากเราจะเข้าสู่การวนรอบเดียวกัน

9.3. Shortest-Path Algorithms การวนรอบดังกล่าวนี้เรียกว่า negative-cost cycle ซึ่งเมื่อเกิดขึ้นในกราฟแล้วก็ไม่สามารถหา shortest paths ได้ การมี Negative-cost edges ไม่ใช่สิ่งที่เสียหายเหมือนกับการมี cycles ในกราฟ เพียงแต่มันจะทำให้การแก้ปัญหายุ่งยากขึ้น (เพื่อความสะดวกเราจะกำหนดให้ shortest path จาก s ไป s มีค่าเป็น 0

9.3. Shortest-Path Algorithms เราจะกล่าวถึงอัลกอริทึมที่ใช้ปัญหานี้ 4 วิธี ในตอนแรกจะกล่าวถึงปัญหา unweighted shortest-path และแก้โดยใช้เวลาเป็น O(|E| + |V|) จากนั้นแสดงการแก้ปัญหา weighted shortest-path โดยสมมุติให้กราฟไม่มี negative edges และมี running time เป็น O (|E| log |V|) เมื่อใช้โครงสร้างข้อมูลเหมาะสม กรณีกราฟมี negative edges มีวิธีแก้ปัญหาอย่างง่ายแต่ใช้เวลาเป็น O (|E| × |V|) สุดท้ายแก้ปัญหา weighted graph ที่เป็น acyclic graphs แบบพิเศษด้วยเวลาที่เป็น linear

9.3.1 Unweighted Shortest Paths v1 v2 v6 v4 v5 v3 v7 Figure 9.10 unweighted directed graph G Figure 9.10 แสดง unweighted graph, G. จาก vertex, s, ใด ๆ จะทำการหา shortest path จาก s ไปยัง vertices อื่นทั้งหมด โดยที่ในเวลานี้เราไม่สนใจว่าจะมีเส้นทางใดบ้าง เราเพียงต้องการความยาวของ shortest paths เท่านั้น เส้นทางที่ใช้จะได้จากการบันทึกเพิ่มเติมเท่านั้น

Figure 9.11 Graph หลังบันทึกโนดเริ่มต้น สมมุติเลือก s ให้เป็น v3 นั่นคือ shortest path จาก s ไป v3 มี length เป็น 0 บันทึกค่านี้ดังในรูป Figure 9.11. v1 v2 v6 v4 v5 v3 v7 Figure 9.11 Graph หลังบันทึกโนดเริ่มต้น

Figure 9.13 Graph หลังหา vertices ทั้งหมดที่มี shortest path เป็น 2 Figure 9.12 Graph หลังหา vertices ทั้งหมดที่มี path length จาก s เป็น 1 v1 v2 v6 v4 v5 v3 v7 1 1 v1 v2 v6 v4 v5 v3 v7 2 Figure 9.13 Graph หลังหา vertices ทั้งหมดที่มี shortest path เป็น 2

Figure 9.14 shortest paths สุดท้าย v1 v2 v6 v4 v5 v3 v7 1 2 3 1 3

9.3.1. Unweighted Shortest Paths วิธีการค้นหาในกราฟที่เรียกว่า breadth-first search: จะทำการประมวลผล vertices เป็นชั้น (layers) กล่าวคือ vertices ที่อยู่ใกล้กับจุดเริ่มต้นจะได้รับการทำงานก่อนและ vertices ที่อยู่ห่างที่สุดจะได้รับการทำงานสุดท้าย รูปที่ Figure 9.15 แสดงตารางเริ่มต้นของอัลกอริทึมที่จะใช้ในการบันทึกความก้าวหน้าในการทำงาน

V Known dv pv V1 F  V2 V3 V4 V5 V6 V7 Figure 9.15 ตารางเริ่มต้นที่ใช้ในการหา unweighted shortest-path

9.3.1. Unweighted Shortest Paths เราจะบันทึกข้อมูล 3 อย่างสำหรับแต่ละ vertex คือ ระยะทางจาก s ไว้ใน dv เริ่มต้นทุก vertices ไม่สามารถไปถึงจากได้ ยกเว้น s, (ซึ่ง path length เป็น 0) รายการใน pv เป็น bookkeeping variable ซึ่งทำให้เราพิมพ์เส้นทางที่ใช้จริงได้ รายการ known ตั้งค่าเป็น true หลังจากที่ vertex ผ่านการประมวลผลแล้ว เริ่มต้นทุกตัวมีค่านี้เป็น unknown รวมทั้ง vertex เริ่มต้นด้วย เมื่อ vertex ถูกตั้งค่าเป็น known แล้วก็ประกันได้ว่าจะไม่มีเส้นทางที่สั้นกว่าและดังนั้นการประมวลผล vertex ดังกล่าวนี้เป็นอันสิ้นสุด

Figure 9.16 Pseudocode สำหรับ unweighted shortest-path algorithm void unweighted ( Vertex s ) { vertex v, w; /*1*/ s.dist = 0; /*2*/ for ( int currDist = 0; currDist < NUM_VERTICES; currDist++) /*3*/ for each vertex v /*4*/ if ( ( !v.known ) && ( v.dist == currDist ) ){ /*5*/ v.known = true; /*6*/ for each w adjacent to v /*7*/ if ( w.dist = INTFINITY ){ /*8*/ w.dist = currDist + 1; /*9*/ w.path = v; } Figure 9.16 Pseudocode สำหรับ unweighted shortest-path algorithm

9.3.1. Unweighted Shortest Paths running time ของอัลกอริทึมเป็น O(|V|2) เพราะมี nested loops ส่วนที่ไม่ดีคือ loop นอกต้องทำจนกระทั่ง NUM_VERTICES -1 ถึงแม้ว่า vertices ทั้งหมดจะเป็น known ตั้งแต่แรก ๆ แล้วก็ตาม ถึงจะใช้การทดสอบพิเศษเพื่อหลีกเลี่ยงสิ่งที่กล่าวมานั้นก็ไม่ช่วยให้ worst-case running time ดีขึ้นดังสภาวะในรูป Figure 9.17 ซึ่งเริ่มที่ vertex v9 v9 v8 v7 v6 v2 v5 v3 v4 v1 Figure 9.17 กรณีเลวร้ายของ unweighted shortest-path algorithm

9.3.1. Unweighted Shortest Paths เราสามารถเพิ่มประสิทธิภาพได้ด้วยวิธีเดียวกับที่ใช้ใน topological sort ที่เวลาหนึ่งจะมี unknown vertices ที่มี dv   อยู่สองประเภทคือ บางตัวมี dv = currDist และ บางตัวมี dv = currDist + 1 ดังนั้นจึงเป็นการเสียเวลาโดยเปล่าประโยชน์ที่จะค้นหาไปทั้งหมดในตารางเพื่อหา vertex ที่ต้องการตามคำสั่งบรรทัดที่ 2 และ 3

9.3.1. Unweighted Shortest Paths เราสามารถปรับปรุงโดยใช้ queue เพียงตัวเดียว ดังนี้ ณ จุดเริ่มต้นรอบการทำงานนั้น ใน queue มีเฉพาะ vertices ที่มีระยะทางเป็น currDist เมื่อเราเพิ่ม adjacent vertices ที่มีระยะ currDist + 1 เราจะประกันได้ว่ามันจะไม่ได้รับการประมวลผลจนกว่า vertices ทั้งหมดที่มีระยะ currDist จะได้รับการประมวลผลเสร็จสิ้น โดยการ enqueue ทางด้านท้าย

9.3.1. Unweighted Shortest Paths อัลกอริทึ่มใหม่แสดงในรูป Figure 9.18 ให้ vertex เริ่มต้นคือ s เป็นพารามิเตอร์ส่งเข้าในโปรแกรม เป็นไปได้ที่ queue อาจจะว่างลงก่อนโดยที่มีบาง vertices ยังไม่ได้เข้าถึงจากโนดเริ่มต้น และโนดเหล่านั้นก็จะถูกกำหนดระยะให้เป็น INFINITY

Figure 9.18 Pseudocode ของ unweighted shortest-path algorithm void unweighted ( Vertex s ) { Queue q; vertex v, w; /*1*/ q = new Queue(); /*2*/ q.enqueue( s ); s.dist = 0; /*3*/ while ( !q.isEmpty() ) { /*4*/ v = q.dequeue; /*5*/ v.known = true; // Not really needed anymore /*6*/ for each w adjacent to v /*7*/ if ( w.dist = INTFINITY ) /*8*/ w.dist = v.dist + 1; /*9*/ w.path = v; /*10*/ q.enqueue( w ); } Figure 9.18 Pseudocode ของ unweighted shortest-path algorithm

9.3.1. Unweighted Shortest Paths เราไม่ใช้ฟิลด์ known อีกต่อไป เนื่องจากว่าเมื่อ vertex ที่ได้รับการประมวลผลแล้วจะไม่เข้าไปใน queue อีกต่อไป Figure 9.19 แสดงค่าต่าง ๆ ที่เปลี่ยนไปในกราฟในระหว่างการทำงานของอัลกอริทึม ฟิลด์ known ยังคงอยู่ก็เพื่อให้การติดตามการเปลี่ยนแปลงของตารางง่ายขึ้นเท่านั้น ด้วยการใช้การวิเคราะห์เช่นเดียวกับที่ใช้ใน topological sort จะได้อัลกอริทึมเป็น O(|E| + |V|), เมื่อใช้ adjacency lists

Figure 9.19 v1 v2 v6 v4 v5 v3 v7 V dv pv V1 F  1 V3 T V2 2 V4 V5 V6 Init V3 dequeue V1 dequeue V6 dequeue V Known dv pv V1 F  1 V3 T V2 2 V4 V5 V6 V7 Q V1 V6 V6 V2 V4 V2 V4

Figure 9.19 cont v1 v2 v6 v4 v5 v3 v7 V dv pv V1 T 1 V3 V2 2 V4 F V5 3 V2 dequeue V4 dequeue V5 dequeue V7 deaueue V Known dv pv V1 T 1 V3 V2 2 V4 F V5 3 V6 V7  Q V4 V5 V5 V7

9.3.2. Dijkstra's Algorithm (Edsger Wybe Dijkstra 1930 – 2002, Netherland) กรณีเป็น weighted graph เรายังคงใช้แนวคิดเดียวกับ unweighted graph ข้อมูลต่าง ๆ ที่ใช้ยังคงเหมือนเดิม แต่ละ vertex ถูกกำหนดเป็น known หรือ unknown เก็บค่าระยะ dv ของแต่ละ vertex เช่นเดิม ระยะทางนี้จะเป็นระยะทางที่สั้นที่สุดจาก s ไป v โดยใช้เฉพาะ vertices ต่าง ๆ ที่เป็น known เป็น vertex ระหว่างทางเท่านั้น บันทึก pv, ซึ่งเป็น vertex สุดท้ายที่ทำให้เกิดการเปลี่ยนแปลงขึ้นกับ dv

9.3.2. Dijkstra's Algorithm วิธีการที่ใช้ในการแก้ปัญหา single-source shortest-path คือ Dijkstra's algorithm เป็นอัลกอริทึมหนึ่งที่เป็น greedy algorithm ซึ่ง greedy algorithms เป็นการแก้ปัญหาเป็น stages โดยใช้สิ่งที่ดูเหมือนว่าดีที่สุดในแต่ละ stage ปัญหาใหญ่ของ greedy algorithms คือบางครั้งมันก็แก้ปัญหาไม่ได้

9.3.2. Dijkstra's Algorithm Dijkstra's algorithm ทำงานเป็น stages เช่นเดียวกับ unweighted shortest-path algorithm ในแต่ละ stage จะทำการเลือก vertex v ตัวหนึ่งที่มีค่า dv น้อยที่สุดในบรรดา unknown vertices และประกาศให้เป็นเส้นทางที่สั้นที่สุดจาก s ไป v ( known) งานที่เหลือใน stage คือการปรับปรุงค่าของ dw ในกรณี unweighted เราตั้งค่าให้ dw = dv + 1 ถ้า dw =  นั่นคือ เราลดค่าของ dw ลงถ้าหากว่า vertex v มีเส้นทางที่สั้นกว่า ถ้าเราใช้วิธีเดียวกันนี้กับกรณี weighted เราก็จะกำหนดให้ dw = dv + cv,w ถ้าค่าใหม่นี้ทำให้ dw ดีขึ้น

พิจารณากราฟในรูป Figure 9.20 9.3.2. Dijkstra's Algorithm พิจารณากราฟในรูป Figure 9.20 Figure 9.21 เป็นสภาวะเริ่มต้น โดยให้ vertex เริ่มต้น s คือ v1 และมีความยาวของเส้นทางเป็น 0 และกำหนดให้ vertex นี้เป็น known เมื่อ v1 เป็น known จะต้องมีการปรับเปลี่ยนรายการบางรายการ vertices ที่เป็น adjacent กับ v1 คือ v2 และ v4 ซึ่งรายการของทั้งสอง vertices ต้องปรับเปลี่ยนดังในรูป Figure 9.22 เลือก v4 แล้วให้เป็น known และมี v3, v5, v6 และ v7 เป็น adjacent ซึ่งมีการเปลี่ยนแปลงดัง Figure 9.23

9.3.2. Dijkstra's Algorithm ต่อไปเลือก v2 มี v4 เป็น adjacent แต่มันเป็น known แล้วจึงไม่ต้องทำอะไรกับมัน v5 ก็เป็น adjacent แต่ไม่มีการปรับเปลี่ยนใด ๆ เนื่องจากระยะที่ผ่านทาง v2 คือ 2+10 = 12 แต่ได้รับรู้ระยะเท่ากับ 3 แล้ว ดู Figure 9.24 แสดงสภาวะหลัง vertices เหล่านี้ถูกเลือก ต่อไปคือ v5 มีระยะ 3 และมี v7 เป็น adjacent แต่ไม่ปรับเปลี่ยนเพราะว่า 3 + 6 > 5 จากนั้นเลือก v3 และปรับเปลี่ยนระยะสำหรับ v6 ลงเป็น 3 + 5 = 8 ดังรูป Figure 9.25 ต่อไปเลือก v7 ซึ่งต้องปรับเปลี่ยน v6 เป็น 5+1 = 6 ดังรูป Figure 9.26 สุดท้ายเลือก v6 ดังรูป Figure 9.27

v1 v2 v6 v4 v5 v3 v7 6 10 1 8 5 4 2 3 v1 v2 v6 v4 v5 v3 v7 6 10 1 8 5 4 2 3 Initial V Known dv pv V1 F V2  V3 V4 V5 V6 V7 After v1 known V Known dv pv V1 T V2 F 2 V3  V4 1 V5 V6 V7

v1 v2 v6 v4 v5 v3 v7 6 10 1 8 5 4 2 3 v1 v2 v6 v4 v5 v3 v7 6 10 1 8 5 4 2 3 After v4 known V Known dv pv V1 T V2 F 2 V3 3 V4 1 V5 V6 9 V7 5 After v2 known V Known dv pv V1 T V2 2 V3 F 3 V4 1 V5 V6 9 V7 5

v1 v2 v6 v4 v5 v3 v7 6 10 1 8 5 4 2 3 v1 v2 v6 v4 v5 v3 v7 6 10 1 8 5 4 2 3 After v5 and v3 known V Known dv pv V1 T V2 2 V3 3 V4 1 V5 V6 F 8 V7 5 After v7 known V Known dv pv V1 T V2 2 V3 3 V4 1 V5 V6 F 6 V7 5 v4

v1 v2 v6 v4 v5 v3 v7 6 10 1 8 5 4 2 3 9.3.2. Dijkstra's Algorithm V dv After v6 known V Known dv pv V1 T V2 2 V3 3 V4 1 V5 V6 6 V7 5 v4

พิจารณา pseudocode ของ Dijkstra's algorithm แต่ละ Vertex เก็บ datafields ต่าง ๆ ที่ใช้ในอัลกอริทึม (Fig. 9.29) กำหนดให้อ่านกราฟเข้าในอะเรย์ของ Vertex และสร้าง adjacency lists โดย routine readGraph Figure 9.30, เป็น initialization routine พิมพ์เส้นทางด้วย recursive routine ใน Figure 9.31 โดยเริ่มพิมพ์ไปตามเส้นทางจนถึง v Figure 9.32 เป็น main algorithm ซึ่งเป็นเพียง for loop ที่ใช้ในการเพิ่มเติมข้อมูลในตาราง

Figure 9.29 Declarations ของ Dijkstra's algorithm class Vertex { public List adj; // Adjacent vertices public boolean known; public DistType dist; // DistType is probably int public Vertex path; // Other fields and methods as needed }

Figure 9.30 Table initialization routine public Vertex createTable( ) { /*1*/ Vertex [ ] t = readGraph( ); // read graph somehow /*2*/ for ( int i = 0; i < t.length; i++ ) /*3*/ t[ i ].known = false; /*4*/ t[ i ].dist = INFINTY; /*5*/ t[ i ].path = null; } /*6*/ NUM_VERTICES = t.length;

Figure 9.31 Routine to print the actual shortest path /* print shortest path to v after dijkstra has run */ /* assume that the path exists */ void printPath ( Vertex v ) { if ( v.path != null ) printPath( v.path ); System.out.print ( " to " ); } System.out.print ( v );

Figure 9.32 Pseudocode ของ Dijkstra's algorithm void dijkstra ( Vertex s ) { vertex v, w; /*1*/ s.dist = 0; /*2*/ for( ; ; ) /*3*/ v = smallest unknown distance vertex; /*4*/ if (v == null ) /*5*/ break; /*6*/ v.known = true; /*7*/ for each w adjacent to v /*8*/ if ( !w.known ) /*9*/ if ( v.dist + cvw < w.dist ) { /* update w */ /*10*/ decrease( w.dist to v.dist + cv,w ); /*11*/ w.path = v; } Figure 9.32 Pseudocode ของ Dijkstra's algorithm

9.3.2. Dijkstra's Algorithm อัลกอริทึมนี้ใช้งานได้ตราบเท่าที่ไม่มี negative cost edge ถ้ามี edge ที่เป็น negative cost อัลกอริทึมอาจให้คำตอบผิดได้ หากอัลกอริทึมที่ใช้เป็นการ scan ไปตามตารางเพื่อหาค่าที่น้อยที่สุด dv เราก็จะใช้การทำงาน O(|V|) หน่วยเวลาในแต่ละ phase การทำงาน ดังนั้นจะต้องใช้เวลาทั้งสิ้นเป็น O(|V|2) หน่วยเวลาตลอดการทำงานของอัลกอริทึม เวลาที่ใช้ในการปรับเปลี่ยนค่า dw เป็นเวลาคงที่ต่อการปรับเปลี่ยนแต่ละครั้ง และต้องปรับเปลี่ยนหนึ่งครั้งต่อหนึ่ง edge เท่านั้น ดังนั้นจำนวนการปรับเปลี่ยนค่านี้ทั้งหมดจึงเป็น O(|E|) รวม running time ทั้งหมดของอัลกอริทึมคือ O(|E| + |V|2) = O(|V|2)

9.3.2. Dijkstra's Algorithm ถ้ากราฟเป็นแบบ dense ที่มี |E| = (|V|2) แล้วอัลกอริทึมนี้ก็จะเป็น linear ในเทอมของจำนวน edges ถ้ากราฟเป็นแบบ sparse ที่มี |E| =  (|V|) การทำงานจะช้ามาก ในกรณีนี้จะจัดเก็บระยะทางไว้ใน priority queue ถ้าใช้โครงสร้างข้อมูลอื่น อาจจะทำให้ time bounds ของ Dijkstra's algorithm ดีขึ้นได้ ในบทที่ 11, จะกล่าวถึงโครงสร้างข้อมูลแบบ Fibonacci heap ซึ่งทำให้ running time เป็น O(|E| + |V| log |V|)

9.3.3. Graphs with Negative Edge Costs ถ้ากราฟมี negative edge costs แล้วก็ไม่สามารถใช้ Dijkstra's algorithm ปัญหาคือ เมื่อมี vertex u ตัวหนึ่งเป็น known แล้ว ก็เป็นไปได้ที่จะมี vertex v ที่เป็น unknown ตัวหนึ่งมีเส้นทางกลับมายัง u ที่เป็นลบได้อีก การใช้อัลกอริทึมสำหรับกราฟแบบ weighted และ unweighted ร่วมกันแก้ปัญหานี้ได้ แต่จะมี running time เพิ่มขึ้นสูงมาก อัลกอริทึมของเราจะไม่ใช้ตัวแปร known อีกต่อไป ทั้งนี้เนื่องจากระหว่างการทำงานของอัลกอริทึมอาจจะมีการเปลี่ยนใจในการเลือกเส้นทางได้

9.3.3. Graphs with Negative Edge Costs เราเริ่มต้นด้วยการบรรจุ s ลงใน queue จากนั้นในแต่ละ stage ให้ dequeue vertex v ตัวหนึ่ง หา vertices w ทั้งหมดที่เป็น adjacent กับ v โดยที่ต้องมี dw > dv + cv,w ให้ update ค่า dw และ pw, แล้วบรรจุ w ลงใน queue ถ้ายังไม่มี โดยอาจใช้การตั้งค่า bit ให้กับ vertex เพื่อเป็นตัวชี้ว่ามันอยู่ใน queue แล้ว ให้ทำซ้ำกระบวนการดังกล่าวจนกว่า queue จะว่าง Figure 9.33 (almost) แสดงการใช้อัลกอริทึมนี้

void weighted_negative( Vertex s ) { Queue q; Vertex v, w; /. 1 void weighted_negative( Vertex s ) { Queue q; Vertex v, w; /*1*/ q = new Queue( ); /*2*/ q.enqueue( s ); // enqueue the start vertex s /*3*/ while( !q.isEmpty ) /*4*/ v = q.dequeue( ); /*5*/ for each w adjacent to v /*6*/ if ( v.dist + cvw < w.dist ) { /*update w */ /*7*/ w.dist = v.dist + cvw ; /*8*/ w.path = v; /*9*/ if ( w is not already in q ) /*10*/ q.enqueue( w ); } Figure 9.33 Pseudocode ของ weighted shortest-path algorithm ที่มี negative edge costs

9.3.4. Acyclic Graphs ถ้าเรารู้ว่ากราฟเป็นแบบ acyclic เราสามารถปรับปรุง Dijkstra's algorithm โดยเปลี่ยนลำดับที่จะเปลี่ยน vertices เป็น known กฏใหม่ คือการเลือก vertices ตามลำดับใน topological order การทำงานของอัลกอริทึมทำได้ในหนึ่ง pass เนื่องจากการเลือกและปรับเปลี่ยนเกิดขึ้นเช่นเดียวกับที่เกิดใน topological sort

9.3.4. Acyclic Graphs กฏการเลือกนี้ทำงานได้เนื่องจากเมื่อ vertex v ถูกเลือกนั้นระยะ dv ไม่สามารถลดลงได้อีกต่อไป เนื่องจากด้วยลำดับตาม topological ordering rule จะไม่มี incoming edges เกิดขึ้นจากโนดที่ยังไม่รู้ได้ การเลือกนี้ไม่ต้องใช้ priority queue และมี running time เป็น O(|E| + |V|) เนื่องจากการเลือกใช้เวลาคงที่

Figure 9.34 Activity-node graph การใช้งาน acyclic graphs ที่สำคัญอย่างหนึ่งคือ critical path analysis ใช้กราฟในรูป Figure 9.34 เป็นตัวอย่าง แต่ละ node แทนกิจกรรมที่ต้องทำและเวลาที่ใช้ทำงานนั้นให้แล้วเสร็จ A(3) B(2) start C(3) D(2) E(1) F(3) G(2) K(4) H(1) finish A(3) Activity A time spent 3 dependency Figure 9.34 Activity-node graph

กราฟในรูป Figure 9.34 เรียกว่า activity-node graph 9.3.4. Acyclic Graphs กราฟในรูป Figure 9.34 เรียกว่า activity-node graph edges เป็นตัวแทนลำดับความสัมพันธ์ ดังนี้ edge (v, w) หมายความว่ากิจกรรม v ต้องแล้วเสร็จก่อนที่กิจกรรม w จะเริ่มต้นได้ ซึ่งหมายความว่ากราฟต้องไม่มีการวนรอบ กิจกรรมใด ๆ ที่ไม่ขึ้นต่อกันสามารถดำเนินการไปได้อย่างคู่ขนานกัน กราฟชนิดดังกล่าวนี้มักใช้สำหรับการจำลองโครงการก่อสร้าง ซึ่งจะใช้ช่วยตอบปัญหาสำคัญ ๆ หลายอย่างด้วยกัน เช่น

9.3.4. Acyclic Graphs หาเวลาที่เร็วที่สุดที่ใช้ในการทำโครงงานให้แล้วเสร็จ (earliest completion time) จากกราฟจะเห็นว่าคำตอบคือ 10 หน่วยเวลาตามเส้นทาง A, C, F, H หาว่ามีกิจกรรมใดบ้างทำเสร็จช้าลงได้และช้าลงได้เป็นเวลาเท่าไรโดยไม่มีผลกระทบต่อเวลาน้อยที่สุดที่ใช้เพื่อให้โครงการแล้วเสร็จ เช่นความล่าช้าของกิจกรรมใดกิจกรรมหนึ่งของ A, C, F, หรือ H จะทำให้เวลาแล้วเสร็จของโครงการมากกว่า 10 หน่วยเวลา ในทางตรงข้ามกิจกรรม B สามารถเสร็จช้าลงได้สองหน่วยเวลาโดยที่ไม่ทำให้เวลาแล้วเสร็จของโครงการช้าลง

Figure 9.35 เป็น event node graph ของกราฟ Figure 9.34 9.3.4. Acyclic Graphs ในการคำนวณสิ่งที่กล่าวมานั้น เราจะเปลี่ยน activity-node graph ไปเป็น event-node graph ดังนี้ แต่ละ event สอดคล้องกับกิจกรรมที่แล้วเสร็จหนึ่ง ๆ และกิจกรรมทั้งหมดที่ขึ้นต่อมัน การเข้าถึง Events จากโนด v ใน event-node graph ไม่อาจทำได้จนกว่า event v จะสมบูรณ์แล้ว อาจต้องใช้ dummy edges และ dummy nodes ในกรณีที่กิจกรรมนั้น ๆ ขึ้นต่อกิจกรรมอื่น ๆ หลายกิจกรรม เพื่อหลีกเลี่ยงความผิดพลาดของการขึ้นต่อกัน Figure 9.35 เป็น event node graph ของกราฟ Figure 9.34

Activity-node graph Event-node graph A(3) B(2) start C(3) D(2) E(1) F(3) G(2) K(4) H(1) finish Activity-node graph X(n) X/n A/3 B/2 start C/3 D/2 E/1 F/3 G/2 K/4 H/1 finish Event-node graph

Figure 9.34 Event-node graph B/2 start C/3 D/2 E/1 F/3 G/2 K/4 H/1 finish 1 2 3 6’ 4 5 6 7’ 8’ 7 8 9 10’ 10 A/3 B/2 C/3 D/2 E/1 K/4 G/2 F/3 H/1 Figure 9.34 Event-node graph

𝐸 𝐶 𝑤 = max (𝑣,𝑤)∈𝐸 (𝐸 𝐶 𝑣 + 𝑐 𝑣,𝑤 ) 9.3.4. Acyclic Graphs ในการคำนวณหาค่า earliest completion time ของโครงการเป็นเพียงการหาเส้นทางที่ยาวที่สุดจาก event แรกไปยัง event สุดท้าย เนื่องจาก event-node graph เป็นกราฟแบบ acyclic ดังนั้นจึงไม่ต้องกังวลกับการวนรอบ ถ้าให้ ECi เป็น earliest completion time สำหรับโนด i แล้ว เราจะใช้กฎดังนี้ EC1 = 0 𝐸 𝐶 𝑤 = max (𝑣,𝑤)∈𝐸 (𝐸 𝐶 𝑣 + 𝑐 𝑣,𝑤 ) Figure 9.36 แสดง earliest completion time ของแต่ละ event ใน event-node graph ในตัวอย่าง

Figure 9.36 Earliest completion times 1 2 3 6’ 4 5 6 7’ 8’ 7 8 9 10’ 10 A/3 B/2 C/3 D/2 E/1 K/4 G/2 F/3 H/1 Figure 9.36 Earliest completion times

𝐿 𝐶 𝑤 = m𝑖𝑛 (𝑣,𝑤)∈𝐸 (𝐿 𝐶 𝑣 − 𝑐 𝑣,𝑤 ) 9.3.4. Acyclic Graphs เราสามารถคำนวณค่าเวลาที่ช้าที่สุด (latest time), LCi, ที่แต่ละ event มีได้โดยไม่มีผลกระทบต่อเวลาที่แล้วเสร็จของโครงการ โดยใช้สูตร: LCn = ECn 𝐿 𝐶 𝑤 = m𝑖𝑛 (𝑣,𝑤)∈𝐸 (𝐿 𝐶 𝑣 − 𝑐 𝑣,𝑤 ) ค่าดังกล่าวเหล่านี้คำนวณได้ในเวลาที่เป็น linear time โดยให้แต่ละ vertex มีรายการของ adjacent ทั้งหมดและ vertices ก่อนหน้าด้วย

latest completion times หาได้โดย reverse topological order 9.3.4. Acyclic Graphs earliest completion times ของ vertices คำนวณได้โดยใช้ topological order และ latest completion times หาได้โดย reverse topological order Figure 9.37. แสดง latest completion times

Figure 9.37 Latest completion times 1 2 3 6’ 4 5 6 7’ 8’ 7 8 9 10’ 10 A/3 B/2 C/3 D/2 E/1 K/4 G/2 F/3 H/1 Figure 9.37 Latest completion times

Figure 9.38 แสดง slack (ตัวเลขตัวที่สาม) ของแต่ละกิจกรรม 9.3.4. Acyclic Graphs The slack time ของแต่ละ edge ใน event-node graph ใช้แทนเวลาที่สามารถล่าช้าลงได้ในการทำกิจกรรมนั้น ๆ ให้แล้วเสร็จโดยไม่ทำให้ทั้งโครงการช้าลง ซึ่งก็คือ Slack(v,w) = LCw – ECv – cv,w Figure 9.38 แสดง slack (ตัวเลขตัวที่สาม) ของแต่ละกิจกรรม มีบางกิจกรรมที่มีค่า slack เป็นศูนย์ นั่นคือกิจกรรมนี้เป็น critical activities ที่จะต้องทำให้แล้วเสร็จตามเวลา และต้องมีอย่างน้อยหนึ่งเส้นทางที่กิจกรรมทั้งหมดมี slack เป็นศูนย์ และเส้นทางนี้ คือ critical path

1 2 3 6’ 4 5 6 7’ 8’ 7 8 9 10’ 10 A/3/0 B/2/2 C/3/0 D/2/1 E/1/2 K/4/2 G/2/2 F/3/0 H/1/0 Figure 9.38 Earliest completion time, Latest completion times, and slack

9.3.5. All-Pairs Shortest Path บางครั้งจำเป็นต้องหาเส้นทางที่สั้นที่สุดระหว่างคู่ของ vertices ทั้งหมดในกราฟ บทที่ 10 จะกล่าวถึงอัลกอริทึม dynamic programming algorithm ที่ปัญหานี้แก้ได้ในเวลา O(|V|3) ในที่นี้จะไม่กล่าวถึงอีก

9.4. Network Flow Problems กำหนดให้มี directed graph G = (V, E) ที่มี edge capacities cv,w ขีดจำกัดของ edge นี้อาจหมายถึงจำนวนน้ำที่ไหลผ่านท่อหรือยานพาหนะในถนนก็ได้ เรามีสอง vertices คือ s เรียกว่า source และ t เรียกว่า sink และใน edge (v, w) ใด ๆ จะมีของไหลผ่านได้สูงสุดเป็น cv,w หน่วย ที่ vertex v ใด ๆ ที่ไม่ใช่ s หรือ t, ของไหลทั้งหมดที่เข้ายัง vertex ต้องเท่ากับของไหลทั้งหมดที่ออกจากมัน

รูปซ้ายมือใน Figure 9.39 มี maximum flow คือ 5, ดังแสดงในรูปขวามือ 9.4. Network Flow Problems ปัญหา maximum flow คือปัญหาในการหาจำนวนสูงสุดของของไหลที่ไหลจาก s ไปยัง t รูปซ้ายมือใน Figure 9.39 มี maximum flow คือ 5, ดังแสดงในรูปขวามือ ดังที่กล่าวมาแล้วว่า แต่ละ edge ไม่สามารถรับของไหลได้เกินกว่าขีดจำกัดของมัน กล่าวคือ vertex และการกระจายของของไหลจะมีรูปแบบอย่างไรก็ได้ตราบเท่าที่การไหลของมันใน edge ไม่เกินขีดจำกัดและยังคงรักษา flow conservation ไว้ได้ (คือของไหลเข้าเท่ากับของไหลออก)

Figure 9.39 A graph (left) and its maximum flow b c d t 3 2 1 4 s a b c d t 3 2 1 Figure 9.39 A graph (left) and its maximum flow

9.4.1 A Simple Maximum-Flow Algorithm การแก้ปัญหาเป็น stages เริ่มด้วยกราฟ G, และสร้างกราฟ Gf และ Gr Gf , เรียกว่า flow graph เพื่อใช้ระบุจำนวนการไหลที่เกิดใน stage หนึ่ง ๆ ของอัลกอริทึม เริ่มต้นด้วย edges ทั้งหมดใน Gf ไม่มีของไหลเลย และหวังว่าหลังจบอัลกอริทึมแล้วจะได้ Gf ที่มี maximum flow Gr, เรียกว่า residual graph ซึ่งบอกให้ทราบว่าจะสามารถเพิ่มการไหลในแต่ละ edge ได้อีกเท่าไหร่ ซึ่งหาได้โดยลบจำนวนการไหลขณะนั้น ๆ ออกจากขีดจำกัดของ edge และเรียก edge ใน Gr ว่า residual edge

9.4.1. A Simple Maximum-Flow Algorithm การทำงานในแต่ละ stage เราจะทำการหาเส้นทางใน Gr จาก s ไป t เรียกเส้นทางนี้ว่า augmenting path ค่าต่ำสุดของ edge บนเส้นทางนี้ก็คือจำนวนการไหลที่เพิ่มขึ้นได้ทุก ๆ edge บนเส้นทาง เราทำโดยปรับเปลี่ยน Gf และคำนวณ Gr ใหม่ เมื่อไม่พบเส้นทางจาก s ไป t ใน Gr, ก็จบการทำงาน อัลกอริทึมนี้เป็นแบบ nondeterministic คือเรามีอิสระที่จะเลือกเส้นทางใดก็ได้จาก s ไป t Figure 9.40 แสดงกราฟเริ่มต้นของ G, Gf, Gr ตามลำดับ

Figure 9.40 สภาวะเริ่มต้นของกราฟ, flow graph, และ residual graph b c d t 3 2 1 4 F r Figure 9.40 สภาวะเริ่มต้นของกราฟ, flow graph, และ residual graph

Figure 9.41 G, Gf, Gr หลังเพิ่มการไหล 2 หน่วยตามเส้นทาง s, b, d, t a b c d t 3 2 1 4 s a b c d t 2 s a b c d t 3 1 4 2 Figure 9.41 G, Gf, Gr หลังเพิ่มการไหล 2 หน่วยตามเส้นทาง s, b, d, t

Figure 9.42 G, Gf, Gr หลังเพิ่มการไหลสองหน่วยตามเส้นทาง s, a, c, t b c d t 3 2 1 4 s a b c d t 2 s a b c d t 1 4 Figure 9.42 G, Gf, Gr หลังเพิ่มการไหลสองหน่วยตามเส้นทาง s, a, c, t

s a b c d t 3 2 1 4 F r Figure 9.43 G, Gf, Gr หลังเพิ่มหนึ่งหน่วยการไหลตามเส้นทาง s, a, d, t — จบการทำงานของอัลกอริทึม

ปัญหาของอัลกอริทึม คือถ้าเราเลือกเส้นทาง s, a, d, t ในครั้งแรก ดังรูป Figure 9.44 ข้างล่าง b c d t 3 2 1 4 F r Figure 9.44 G, Gf, Gr ถ้าเริ่มต้นเลือกที่จะเพิ่มสามหน่วยการไหลตามเส้นทาง s, a, d, t — จะจบการทำงานด้วยผลที่ไม่ดี

9.4.1. A Simple Maximum-Flow Algorithm เพื่อแก้ปัญหาดังกล่าว เราต้องให้อัลกอริทึมของเราเปลี่ยนใจได้ในระหว่างการทำงาน โดย edge (v, w) ที่มีการไหล fv,w ใน flow graph ให้ทำการเพิ่ม edge ลงใน residual graph (w, v) ด้วยการไหล fv,w ผลก็คืออัลกอริทึมจะสามารถเปลี่ยนการตัดสินใจโดยส่งของไหลกลับในทิศทางตรงกันข้ามได้

9.4.1. A Simple Maximum-Flow Algorithm เริ่มต้นจากกราฟเดิม และเลือก augmenting path s, a, d, t, จะได้กราฟในรูป Figure 9.45 จะเห็นว่าใน residual graph นั้นมี edge ระหว่าง a และ d ทั้งสองทิศทางซึ่งสามารถส่งผ่านหนึ่งหน่วยของไหลจาก a ไป d หรือได้ 3 หน่วยในทางตรงข้าม จากนั้นเลือก augmenting path s, b, d, a, c, t ด้วยขนาด 2 หน่วยของไหล โดยไหลจาก d ไป a สองหน่วยซึ่งเป็นการลดการไหลลงสองหน่วยใน edge (a, d) ซึ่งก็คือการเปลี่ยนใจนั่นเอง รูป Figure 4.6 แสดงกราฟใหม่ที่ได้ อัลกอริทึมจะหยุดทำงานเพราะไม่มี augmenting path อีกแล้ว

Figure 9.45 Graphs หลังเพิ่มสามหน่วยการไหลตามเส้นทาง s, a, d, t b c d t 3 2 1 4 F r 3 Figure 9.45 Graphs หลังเพิ่มสามหน่วยการไหลตามเส้นทาง s, a, d, t

Figure 9.46 Graphs หลังเพิ่มสองหน่วยของไหลในเส้นทาง s, b, d, a, c, t 3 2 1 4 F r Figure 9.46 Graphs หลังเพิ่มสองหน่วยของไหลในเส้นทาง s, b, d, a, c, t

9.4.1. A Simple Maximum-Flow Algorithm ถ้าค่าขีดจำกัดทั้งหมดเป็นเลขจำนวนเต็มและการไหลสูงสุดเป็น f ก็จะใช้ stage ในการทำงานเพียง f stage เนื่องจากแต่ละ augmenting path จะสามารถเพิ่มค่าการไหลได้อย่างน้อย 1 หน่วย และดังนั้น running time ที่ใช้ คือ O(f · |E|), เนื่องจากว่าเราสามารถตรวจหา augmenting path ได้ในเวลา O(|E|) หน่วยเวลาโดยการใช้อัลกอริทึมของ unweighted shortest-path algorithm ตัวอย่างคลาสสิคของภาวะที่ก่อให้เกิด running time ที่ไม่ดีแสดงในรูป Figure 9.47

Figure 9.47 The classic bad case for augmenting 1 000 000 1 000 000 1 a b 1 000 000 1 000 000 t Figure 9.47 The classic bad case for augmenting ด้วยการสังเกตุจะพบว่าการไหลสูงสุดคือ 2,000,000 ด้วยการส่งการไหล 1,000,000 ลงในแต่ละข้าง แต่การเลือกแบบสุ่มอาจเป็นได้ที่มีการเลือกที่จะส่งผ่านตามเส้นทาง a , b ซึ่งต้องทำงานถึง 2,000,000 ครั้ง

9.4.1. A Simple Maximum-Flow Algorithm เพื่อไม่ให้เกิดปัญหาที่กล่าวข้างบน เราจึงต้องทำการเลือก augmenting path ที่สามารถเพิ่มการไหลได้สูงสุดเสมอ ถ้าให้ capmax เป็นขีดจำกัดสูงสุดของ edge แล้วก็จะได้ว่าเราจะต้องใช้จำนวนครั้ง O(|E| log capmax) เพื่อหาการไหลสูงสุด เนื่องจากต้องใช้เวลา O(|E| log |V|) สำหรับการคำนวณของ augmenting path หนึ่ง ๆ นั่นคือขอบเขตเวลาที่ใช้จะเป็น O(|E|2 log |V| log capmax) ถ้าขีดจำกัดเป็นเลขจำนวนเต็มขนาดเล็ก ๆ แล้วก็จะได้ขอบเขตเวลาเป็น O(|E|2 log |V|)

9.4.1. A Simple Maximum-Flow Algorithm อีกวิธีหนึ่งในการเลือก augmenting paths คือจะเลือกเส้นทางที่มีจำนวน edges น้อยที่สุดเสมอ ด้วยหวังว่าการเลือกเช่นนี้จะทำให้ได้ edge ที่มีขีดจำกัดน้อย ๆ จำนวนน้อยลงนั่นเอง กรณีเช่นนี้ ต้องใช้การเลือก augmenting path จำนวน O(|E|· |V|) ครั้ง แต่ละครั้งใช้เวลา O(|E|) ด้วยการใช้ unweighted shortest-path algorithm จะได้ขอบเขตของ running time เป็น O(|E|2|V|)