1 00:00:06,580 --> 00:00:09,580 SRINI DEVADAS: So, so far we haven't really 2 00:00:09,580 --> 00:00:11,810 done much with the data structures 3 00:00:11,810 --> 00:00:14,494 outside of Python lists. 4 00:00:14,494 --> 00:00:15,910 We looked at two dimensional lists 5 00:00:15,910 --> 00:00:18,490 but, you know, they are still lists. 6 00:00:18,490 --> 00:00:21,220 And so this particular puzzle that we're 7 00:00:21,220 --> 00:00:23,920 going to do today, I-- 8 00:00:23,920 --> 00:00:27,350 has a graph structure associated with it. 9 00:00:27,350 --> 00:00:30,730 So for the first time, at least in this class, 10 00:00:30,730 --> 00:00:34,750 we'll be looking at traversing graphs, 11 00:00:34,750 --> 00:00:39,820 and we're going to do this in a recursive way. 12 00:00:39,820 --> 00:00:43,930 And, also, we'll have a graph representation 13 00:00:43,930 --> 00:00:45,680 using dictionaries. 14 00:00:45,680 --> 00:00:47,990 So most of you have probably seen dictionaries. 15 00:00:47,990 --> 00:00:50,370 If you haven't, I'm going to explain them. 16 00:00:50,370 --> 00:00:53,110 They're essentially ways that you 17 00:00:53,110 --> 00:00:58,480 can index into lists, not just using 18 00:00:58,480 --> 00:01:03,850 nonzero integers, indices, zero through n, or what have you. 19 00:01:03,850 --> 00:01:08,530 But things like strings or tuples, 20 00:01:08,530 --> 00:01:12,610 and so they're just more general and-- they're more general data 21 00:01:12,610 --> 00:01:15,160 structure than Python lists. 22 00:01:15,160 --> 00:01:18,040 And so they're very convenient when 23 00:01:18,040 --> 00:01:22,570 it comes to representing graphs and traversing graphs. 24 00:01:22,570 --> 00:01:27,160 So the puzzle we can look at is, as always, 25 00:01:27,160 --> 00:01:29,770 is a little bit contrived. 26 00:01:29,770 --> 00:01:33,040 It's about weekend dinner scheduling. 27 00:01:33,040 --> 00:01:35,950 So you have a bunch of friends. 28 00:01:35,950 --> 00:01:46,630 And let me draw your social network here, 29 00:01:46,630 --> 00:01:48,440 or someone's social network. 30 00:01:48,440 --> 00:01:55,620 So we won't name names, but each node in this graph 31 00:01:55,620 --> 00:02:02,740 represents a friend, and a couple more. 32 00:02:06,340 --> 00:02:10,630 And so that's the set of friends, a through h, 33 00:02:10,630 --> 00:02:13,750 and that won't be particularly interesting as a graph. 34 00:02:13,750 --> 00:02:15,970 If it just had nodes, you want to add edges 35 00:02:15,970 --> 00:02:19,240 to it, what do these edges represent? 36 00:02:19,240 --> 00:02:22,420 Well, you like all of your friends, 37 00:02:22,420 --> 00:02:26,740 but your friends don't necessarily like each other. 38 00:02:26,740 --> 00:02:32,110 And so an edge between nodes-- 39 00:02:32,110 --> 00:02:42,810 so nodes are friends, and an edge between a pair of nodes 40 00:02:42,810 --> 00:02:47,261 implies a dislike relationship. 41 00:02:47,261 --> 00:02:47,760 All right. 42 00:02:51,250 --> 00:02:54,220 So b dislikes c, and it's symmetric. 43 00:02:54,220 --> 00:02:56,250 I mean, you could argue that dislikes is not 44 00:02:56,250 --> 00:03:00,050 necessarily symmetric, but we'll just call it that. 45 00:03:00,050 --> 00:03:02,610 That implies that c dislikes b as well. 46 00:03:02,610 --> 00:03:05,360 So this is not necessarily a directed graph. 47 00:03:05,360 --> 00:03:07,010 Some of the time, especially when 48 00:03:07,010 --> 00:03:11,390 you're doing group planning, going from point A to point B, 49 00:03:11,390 --> 00:03:14,150 you have to take into account one-way streets, 50 00:03:14,150 --> 00:03:16,460 and so you have directed graphs. 51 00:03:16,460 --> 00:03:21,000 But many a time, you can get away with undirected graphs. 52 00:03:21,000 --> 00:03:23,840 So you just-- the existence of an edge between B and C 53 00:03:23,840 --> 00:03:28,250 implies that in a traversal, you can get from B to C or C to B, 54 00:03:28,250 --> 00:03:31,710 and there's no direction there. 55 00:03:31,710 --> 00:03:34,349 And so I'm going to fill in the rest of this, 56 00:03:34,349 --> 00:03:36,515 and then get to the question that we want to answer. 57 00:03:40,990 --> 00:03:42,390 And so that's your-- 58 00:03:42,390 --> 00:03:44,370 your friend graph. 59 00:03:44,370 --> 00:03:51,120 And it also has these six or seven dislike relationships. 60 00:03:51,120 --> 00:03:57,220 And your job is to, well, keep all your friends happy. 61 00:03:57,220 --> 00:04:00,600 And the way you're going to do that is by-- 62 00:04:00,600 --> 00:04:04,000 is by having a couple of parties on the weekend. 63 00:04:04,000 --> 00:04:06,580 So this is a regular weekend. 64 00:04:06,580 --> 00:04:09,480 Let's call it Friday and Saturday-- 65 00:04:09,480 --> 00:04:11,360 Friday and Saturday night parties. 66 00:04:11,360 --> 00:04:14,980 And the only constraint-- 67 00:04:14,980 --> 00:04:16,450 actually, there's two constraints. 68 00:04:16,450 --> 00:04:20,899 There's-- the two constraints that you need to follow are 69 00:04:20,899 --> 00:04:23,860 satisfy when you have these two parties. 70 00:04:23,860 --> 00:04:29,420 So you have your Friday party and your Saturday party, 71 00:04:29,420 --> 00:04:32,370 is you can't leave anybody out, right? 72 00:04:32,370 --> 00:04:39,455 So you-- effectively, they're constrained as each friend-- 73 00:04:45,150 --> 00:04:45,930 --comes to-- 74 00:04:50,710 --> 00:04:53,640 --exactly one party. 75 00:04:53,640 --> 00:04:58,160 No one gets left out, no one comes to both. 76 00:04:58,160 --> 00:05:00,870 So that's fair. 77 00:05:00,870 --> 00:05:04,860 And then the second constraint as you can probably guess 78 00:05:04,860 --> 00:05:06,325 is no pair-- 79 00:05:10,140 --> 00:05:14,460 --of friends who dislike each other, 80 00:05:14,460 --> 00:05:17,549 they're not friendly, they're your friends, 81 00:05:17,549 --> 00:05:18,840 can be invited on the same day. 82 00:05:38,710 --> 00:05:42,100 And so you want an algorithm that is 83 00:05:42,100 --> 00:05:43,870 going to give you a schedule. 84 00:05:43,870 --> 00:05:46,660 And, obviously, the schedule is not necessarily unique. 85 00:05:46,660 --> 00:05:52,690 I mean, if you had a bunch of happy-go-lucky low overhead 86 00:05:52,690 --> 00:05:54,530 friends, you know, they all like each other 87 00:05:54,530 --> 00:05:59,992 and you could just randomly break them up into two groups. 88 00:05:59,992 --> 00:06:01,450 You can think of it as a partition. 89 00:06:01,450 --> 00:06:06,590 A partition is a grouping where-- 90 00:06:06,590 --> 00:06:09,710 then you have anything in a set of nodes, for example, 91 00:06:09,710 --> 00:06:11,620 and you partition it, you're essentially 92 00:06:11,620 --> 00:06:17,140 saying you're breaking it up into two groups, 93 00:06:17,140 --> 00:06:19,000 such that each node is in exactly one 94 00:06:19,000 --> 00:06:24,136 group, and each node-- 95 00:06:24,136 --> 00:06:25,510 and then we have another property 96 00:06:25,510 --> 00:06:27,430 associated with the partition that 97 00:06:27,430 --> 00:06:30,730 corresponds to the edges between these nodes. 98 00:06:30,730 --> 00:06:32,190 But we'll get to that in just-- 99 00:06:32,190 --> 00:06:33,435 just a minute. 100 00:06:33,435 --> 00:06:34,310 Yeah, go ahead, Fadi. 101 00:06:34,310 --> 00:06:37,740 AUDIENCE: How are we going to deal with the-- with FGH, 102 00:06:37,740 --> 00:06:40,031 because we only have two parties and-- 103 00:06:40,031 --> 00:06:41,530 SRINI DEVADAS: That's exactly right. 104 00:06:41,530 --> 00:06:48,670 So-- so the purpose of this puzzle is to determine whether 105 00:06:48,670 --> 00:06:52,600 you can actually do this or not, and so you are certainly 106 00:06:52,600 --> 00:06:55,480 welcome to-- 107 00:06:55,480 --> 00:06:57,370 when you write a computer program-- 108 00:06:57,370 --> 00:07:01,150 or when we write a computer program here, it might say, 109 00:07:01,150 --> 00:07:04,060 no can do, you know, find a different set of friends 110 00:07:04,060 --> 00:07:06,640 or maybe identify a problem case. 111 00:07:06,640 --> 00:07:08,980 You know, there's one person who dislikes 112 00:07:08,980 --> 00:07:10,750 all of your other friends. 113 00:07:10,750 --> 00:07:12,850 Maybe you should drop that person, right? 114 00:07:12,850 --> 00:07:15,580 And so you can imagine that-- 115 00:07:15,580 --> 00:07:18,970 that you would not necessarily be 116 00:07:18,970 --> 00:07:24,130 able to satisfy these two constraints for all graphs, 117 00:07:24,130 --> 00:07:24,670 right? 118 00:07:24,670 --> 00:07:27,670 And so that's really the essence of the puzzle. 119 00:07:27,670 --> 00:07:29,610 For what kind of graphs? 120 00:07:29,610 --> 00:07:33,260 And this, it turns out that a fairly famous kind of graph, 121 00:07:33,260 --> 00:07:34,270 does-- 122 00:07:34,270 --> 00:07:37,870 does this puzzle have a solution, right? 123 00:07:37,870 --> 00:07:42,010 And so you-- you have to look at this 124 00:07:42,010 --> 00:07:44,110 and you kind of go, and the first thing that 125 00:07:44,110 --> 00:07:51,640 occurred to you was, hey, if I had F, G, and H, if I invite F 126 00:07:51,640 --> 00:07:57,010 on Friday, I have to invite G and H on Saturday. 127 00:07:57,010 --> 00:08:00,130 But then G and H don't like each other, right? 128 00:08:00,130 --> 00:08:02,650 So that's a problem, right? 129 00:08:02,650 --> 00:08:05,380 And so in this particular case, you've 130 00:08:05,380 --> 00:08:10,180 identified this cycle that indicates that this problem is 131 00:08:10,180 --> 00:08:11,650 not solvable. 132 00:08:11,650 --> 00:08:18,610 But, let's say, that somehow you've placated G 133 00:08:18,610 --> 00:08:19,640 and you patch-- 134 00:08:19,640 --> 00:08:21,400 they're patched up. 135 00:08:21,400 --> 00:08:21,970 All right. 136 00:08:21,970 --> 00:08:26,050 So-- so you end up having a fairly complex graph structure 137 00:08:26,050 --> 00:08:28,750 that looks like this, right? 138 00:08:28,750 --> 00:08:30,460 And now what happens? 139 00:08:30,460 --> 00:08:33,494 Now, is there-- is there a solution to this problem, 140 00:08:33,494 --> 00:08:34,885 to this particular puzzle? 141 00:08:40,429 --> 00:08:44,150 I mean, A can come on any day so let's ignore A. All right. 142 00:08:44,150 --> 00:08:46,520 A is easy. 143 00:08:46,520 --> 00:08:49,820 Suppose you invite-- you can try and figure this out 144 00:08:49,820 --> 00:08:57,620 by saying let's go ahead and invite B on Friday. 145 00:08:57,620 --> 00:09:00,750 So what does that imply? 146 00:09:00,750 --> 00:09:02,910 That immediately implies that? 147 00:09:02,910 --> 00:09:05,490 C is on Saturday, right? 148 00:09:05,490 --> 00:09:08,330 What does that imply? 149 00:09:08,330 --> 00:09:09,770 D is on Friday, right? 150 00:09:09,770 --> 00:09:12,135 So you see-- you see how this is going to go. 151 00:09:12,135 --> 00:09:13,010 What does that imply? 152 00:09:15,770 --> 00:09:18,140 E and F are on-- 153 00:09:18,140 --> 00:09:19,380 are on Saturday. 154 00:09:19,380 --> 00:09:22,340 So I have E and F on Saturday, OK? 155 00:09:22,340 --> 00:09:25,100 And then what does that imply? 156 00:09:25,100 --> 00:09:28,810 That F being on Saturday implies that G, H, and I 157 00:09:28,810 --> 00:09:32,530 have to be on Friday, right? 158 00:09:32,530 --> 00:09:34,810 And then I-- don't forget A. So let's just stick 159 00:09:34,810 --> 00:09:36,610 A in here to even things out. 160 00:09:36,610 --> 00:09:38,250 All right. 161 00:09:38,250 --> 00:09:41,910 So-- so we kind of did an algorithm here, 162 00:09:41,910 --> 00:09:44,340 we executed an algorithm, right? 163 00:09:44,340 --> 00:09:52,590 And it turns out that graphs that can be partitioned 164 00:09:52,590 --> 00:09:55,440 in this manner are-- 165 00:09:55,440 --> 00:09:58,680 I have a special name. 166 00:09:58,680 --> 00:10:01,815 They're called bipartite graphs. 167 00:10:01,815 --> 00:10:03,180 Bipartite graphs. 168 00:10:03,180 --> 00:10:03,930 I'll write it out. 169 00:10:13,850 --> 00:10:16,940 And that-- the reason they're called bipartite graphs 170 00:10:16,940 --> 00:10:23,120 is if you have a bipartite graph, 171 00:10:23,120 --> 00:10:27,935 you can always draw it in this fashion. 172 00:10:31,810 --> 00:10:37,990 Where you have A, C, E, F, and then 173 00:10:37,990 --> 00:10:49,470 you have B, D, G, H, I, such that you never see edges 174 00:10:49,470 --> 00:10:51,900 like this or like that. 175 00:10:51,900 --> 00:10:54,170 All the edges go from left to right-- 176 00:10:54,170 --> 00:10:54,990 or right to left. 177 00:10:54,990 --> 00:10:56,460 They're undirected. 178 00:10:56,460 --> 00:10:57,390 OK. 179 00:10:57,390 --> 00:11:00,030 So that's really a bipartite graph. 180 00:11:00,030 --> 00:11:02,490 And if I draw this out-- 181 00:11:02,490 --> 00:11:04,350 oop, don't need that. 182 00:11:09,060 --> 00:11:13,262 C goes to B and D. A goes nowhere. 183 00:11:13,262 --> 00:11:19,594 E goes to D. And F goes to a bunch of different places. 184 00:11:19,594 --> 00:11:20,094 Yeah. 185 00:11:26,360 --> 00:11:27,987 So you're allowed to have-- 186 00:11:27,987 --> 00:11:29,320 this will still be a bipartite-- 187 00:11:29,320 --> 00:11:32,620 I won't-- this is not the graph that we had, 188 00:11:32,620 --> 00:11:35,050 but it's not that-- 189 00:11:35,050 --> 00:11:38,140 the edges can be crossing edges. 190 00:11:38,140 --> 00:11:38,920 OK. 191 00:11:38,920 --> 00:11:41,770 They just all have to go from left to right. 192 00:11:41,770 --> 00:11:44,470 You just can't have an edge between A and C, 193 00:11:44,470 --> 00:11:46,990 or C and A. You can't have an edge between D 194 00:11:46,990 --> 00:11:48,560 and H, et cetera. 195 00:11:48,560 --> 00:11:49,270 All right. 196 00:11:49,270 --> 00:11:51,790 So you want to-- you have to be able to separate out 197 00:11:51,790 --> 00:11:56,830 the nodes such that there are no edges in this set of nodes, 198 00:11:56,830 --> 00:11:58,480 and no edges between this set of nodes, 199 00:11:58,480 --> 00:12:00,380 and no edges between that set of nodes. 200 00:12:00,380 --> 00:12:03,250 And this is just a topological property 201 00:12:03,250 --> 00:12:06,988 that corresponds to bipartite graphs. 202 00:12:06,988 --> 00:12:10,690 And there's another property that essentially 203 00:12:10,690 --> 00:12:13,600 is equivalent to our puzzle, which says, 204 00:12:13,600 --> 00:12:16,480 bipartite graphs are two colorable. 205 00:12:16,480 --> 00:12:21,860 And it's obvious as to why a bipar-- 206 00:12:21,860 --> 00:12:23,500 bipartite graph is two colorable, 207 00:12:23,500 --> 00:12:26,350 and what does it mean to be two colorable. 208 00:12:26,350 --> 00:12:29,800 Well, you need to color each node 209 00:12:29,800 --> 00:12:37,960 with two colors, in this case, Friday and Saturday, such 210 00:12:37,960 --> 00:12:54,940 that no pair of nodes with an edge between them 211 00:12:54,940 --> 00:12:55,780 have the same color. 212 00:12:58,511 --> 00:13:00,760 So exactly equivalent to what we've talked about here. 213 00:13:03,440 --> 00:13:10,320 So our goal now is to discover whether a bipartite graph-- 214 00:13:10,320 --> 00:13:12,000 or a given graph, excuse me-- 215 00:13:12,000 --> 00:13:13,690 is bipartite or not. 216 00:13:13,690 --> 00:13:16,459 Once you know that a graph is bipartite, 217 00:13:16,459 --> 00:13:18,000 you know it's two colorable, you know 218 00:13:18,000 --> 00:13:22,820 it's a solution to our problem, to our puzzle problem. 219 00:13:22,820 --> 00:13:23,422 OK. 220 00:13:23,422 --> 00:13:25,380 And, of course, in order to do this, and if you 221 00:13:25,380 --> 00:13:26,650 had a graph with-- 222 00:13:26,650 --> 00:13:31,590 you had thousands of friends and, perhaps, tens of thousands 223 00:13:31,590 --> 00:13:35,040 of edges, and you need to discover it's not your dinner 224 00:13:35,040 --> 00:13:35,822 problem, maybe. 225 00:13:35,822 --> 00:13:38,280 But you need to discover whether the graph is two colorable 226 00:13:38,280 --> 00:13:43,140 or not, then you need to write a computer program for this. 227 00:13:43,140 --> 00:13:45,060 You need a graph representation. 228 00:13:45,060 --> 00:13:47,255 You need to do this traversal, et cetera, et cetera. 229 00:13:47,255 --> 00:13:47,880 Go ahead, Josh. 230 00:13:47,880 --> 00:13:50,282 AUDIENCE: If a graph is two colorable, 231 00:13:50,282 --> 00:13:51,240 is it always bipartite? 232 00:13:51,240 --> 00:13:52,090 SRINI DEVADAS: Yes. 233 00:13:52,090 --> 00:13:54,150 They're equivalent definitions. 234 00:13:54,150 --> 00:13:55,320 Absolutely right. 235 00:13:55,320 --> 00:13:58,740 Because what would happen is if you can color it, 236 00:13:58,740 --> 00:14:04,300 then it means that you can take all of the red colors, you-- 237 00:14:04,300 --> 00:14:07,230 red could be equivalent to Friday, and-- 238 00:14:07,230 --> 00:14:09,420 and then blue could be equivalent to Saturday, 239 00:14:09,420 --> 00:14:14,070 and all of the red colors could be placed on the left, and-- 240 00:14:14,070 --> 00:14:17,170 and the blue on the right. 241 00:14:17,170 --> 00:14:17,670 Fadi. 242 00:14:17,670 --> 00:14:20,600 AUDIENCE: But then a graph with no edges is one colorable 243 00:14:20,600 --> 00:14:22,862 but also, by definition, considered bipartite? 244 00:14:22,862 --> 00:14:23,860 SRINI DEVADAS: Yes. 245 00:14:23,860 --> 00:14:24,630 That's it. 246 00:14:24,630 --> 00:14:27,570 That-- there's always pathological cases, 247 00:14:27,570 --> 00:14:32,190 and they're usually things that get swept under the rug. 248 00:14:32,190 --> 00:14:34,820 But one colorable is-- 249 00:14:34,820 --> 00:14:37,290 it is considered two colorable. 250 00:14:37,290 --> 00:14:41,770 You can color it the two colors, that's really what it is. 251 00:14:41,770 --> 00:14:45,540 Let's talk about cycles to get a sense for this property. 252 00:14:45,540 --> 00:14:49,080 So immediately I think you recognize 253 00:14:49,080 --> 00:14:51,820 that when you have something like, 254 00:14:51,820 --> 00:14:55,890 I forget what it was exactly, FGI or FGH, 255 00:14:55,890 --> 00:15:00,240 whatever, that if you had a cycle like this, 256 00:15:00,240 --> 00:15:03,300 that a graph is not bipartite, right? 257 00:15:03,300 --> 00:15:09,550 A three cycle is not bipartite. 258 00:15:12,500 --> 00:15:15,650 Is any cycle a problem? 259 00:15:15,650 --> 00:15:17,480 If I have a cycle in the graph, which 260 00:15:17,480 --> 00:15:22,700 means that I can go from one node back to the same node 261 00:15:22,700 --> 00:15:27,837 through a sequence of edges and, obviously, traversing nodes, 262 00:15:27,837 --> 00:15:28,670 do I have a problem? 263 00:15:28,670 --> 00:15:32,090 Is that can be immediately declared that the graph is not 264 00:15:32,090 --> 00:15:32,720 bipartite? 265 00:15:32,720 --> 00:15:33,219 Yeah. 266 00:15:33,219 --> 00:15:34,660 Go ahead, Julia, why not? 267 00:15:34,660 --> 00:15:37,485 AUDIENCE: Well, like an even cycle if it was, 268 00:15:37,485 --> 00:15:38,772 for example, A, B, C & D-- 269 00:15:38,772 --> 00:15:39,980 SRINI DEVADAS: Ah, beautiful. 270 00:15:39,980 --> 00:15:42,420 That's exactly what I wanted to bring up. 271 00:15:42,420 --> 00:15:47,610 So if I had something like A, B, C, D, right? 272 00:15:47,610 --> 00:15:56,090 That's clearly a cyclic graph, and I could put on A and C 273 00:15:56,090 --> 00:16:02,550 on here, and B and D up here, and clearly there's 274 00:16:02,550 --> 00:16:05,310 no edge between A and C, there's no edge between B and D. 275 00:16:05,310 --> 00:16:07,650 There's an edge between A and B, there's 276 00:16:07,650 --> 00:16:10,350 an edge between C and D, and there's also 277 00:16:10,350 --> 00:16:15,160 an edge between A and D and C and B. So as I mentioned, 278 00:16:15,160 --> 00:16:17,460 you're allowed crossing edges. 279 00:16:17,460 --> 00:16:20,220 They all have to go from left to right or right 280 00:16:20,220 --> 00:16:23,400 to left, whichever way you're looking at it. 281 00:16:23,400 --> 00:16:28,900 So interestingly enough, I mean, this is two colorable. 282 00:16:28,900 --> 00:16:31,270 But when you get to-- 283 00:16:31,270 --> 00:16:33,710 when you get to odd cycles-- 284 00:16:33,710 --> 00:16:37,440 so I'll draw one out here-- 285 00:16:37,440 --> 00:16:42,075 in the middle, and let's say I want to mark these nodes-- 286 00:16:46,500 --> 00:16:50,000 --the names, but let's say that you have a five cycle now. 287 00:16:50,000 --> 00:16:50,500 All right. 288 00:16:50,500 --> 00:16:54,510 If you have a five cycle, think about it. 289 00:16:54,510 --> 00:16:58,330 You-- you are going to go-- color this red. 290 00:16:58,330 --> 00:16:59,830 So let me just go ahead and say this 291 00:16:59,830 --> 00:17:02,770 is red, which means this needs to be blue, 292 00:17:02,770 --> 00:17:04,599 that needs to be blue. 293 00:17:04,599 --> 00:17:08,530 This blue implies this needs to be red, which now implies 294 00:17:08,530 --> 00:17:09,849 that this needs to be blue. 295 00:17:09,849 --> 00:17:13,420 And it's like, whoops, that's a problem, right? 296 00:17:13,420 --> 00:17:18,810 So, interestingly enough, the odd evenness 297 00:17:18,810 --> 00:17:23,020 of the parity of a cycle determines 298 00:17:23,020 --> 00:17:25,480 whether a graph is bipartite or not, 299 00:17:25,480 --> 00:17:32,030 it doesn't mean that a graph that only has four cycles in it 300 00:17:32,030 --> 00:17:39,560 is necessarily bipartite, because there 301 00:17:39,560 --> 00:17:44,150 could be other reasons for it not to be-- 302 00:17:44,150 --> 00:17:46,430 not to be bipartite. 303 00:17:46,430 --> 00:17:50,752 Because you don't know about the other cycles in the graph. 304 00:17:50,752 --> 00:17:51,710 I mean, they could be-- 305 00:17:51,710 --> 00:17:53,420 you say it's only up to four cycles. 306 00:17:53,420 --> 00:17:55,400 Well, there could be a three cycle in it, 307 00:17:55,400 --> 00:17:57,560 and things get pretty complicated when 308 00:17:57,560 --> 00:17:59,857 you have things like that. 309 00:17:59,857 --> 00:18:01,190 There's a lot of cycles in here. 310 00:18:01,190 --> 00:18:03,500 This is a cycle like that, there's a cycle like this, 311 00:18:03,500 --> 00:18:05,270 and the moment you put an edge in here, 312 00:18:05,270 --> 00:18:08,760 now you're saying this goes over here, goes like this. 313 00:18:08,760 --> 00:18:10,100 There's a three cycle here. 314 00:18:10,100 --> 00:18:11,930 But even if this didn't exist, there 315 00:18:11,930 --> 00:18:14,520 would be a five cycle, et cetera, et cetera. 316 00:18:14,520 --> 00:18:16,760 So there's a lot of cycles and graphs, right? 317 00:18:16,760 --> 00:18:20,450 And your algorithm, essentially, needs 318 00:18:20,450 --> 00:18:25,930 to ensure that for-- that every cycle is an even cycle. 319 00:18:25,930 --> 00:18:26,990 OK. 320 00:18:26,990 --> 00:18:31,580 And that is exactly equivalent to coloring it with two colors. 321 00:18:31,580 --> 00:18:32,540 OK. 322 00:18:32,540 --> 00:18:41,360 So we, obviously, need to have a way of stopping here 323 00:18:41,360 --> 00:18:44,090 in the sense that when you have a cycle, 324 00:18:44,090 --> 00:18:48,920 you are going to come back and the cycle may be fine 325 00:18:48,920 --> 00:18:50,810 because it's an even cycle. 326 00:18:50,810 --> 00:18:54,410 But you, obviously, can't keep going around the cycle 327 00:18:54,410 --> 00:18:56,690 without terminating in a computer program. 328 00:18:56,690 --> 00:19:00,960 So we're going to have to do a recursive search. 329 00:19:00,960 --> 00:19:03,680 Which has interesting termination conditions, 330 00:19:03,680 --> 00:19:05,360 you know, as opposed to the divide 331 00:19:05,360 --> 00:19:10,264 and conquer, or even the iterative enumeration 332 00:19:10,264 --> 00:19:12,680 that we did where it was pretty clear what the termination 333 00:19:12,680 --> 00:19:13,550 condition was. 334 00:19:13,550 --> 00:19:15,530 That the base case was fairly straightforward 335 00:19:15,530 --> 00:19:18,560 because you came down to a list of length 1, 336 00:19:18,560 --> 00:19:24,050 or you had something where you broke things up to the point 337 00:19:24,050 --> 00:19:26,300 where you had really small problems 338 00:19:26,300 --> 00:19:28,910 and that corresponded to your base case, right? 339 00:19:28,910 --> 00:19:30,535 But cycle detection, especially when 340 00:19:30,535 --> 00:19:31,910 you're doing recursive traversal, 341 00:19:31,910 --> 00:19:33,980 can be pretty tricky. 342 00:19:33,980 --> 00:19:36,470 And we also, of course, as I said initially, 343 00:19:36,470 --> 00:19:40,620 we have to be able to represent this graph structure. 344 00:19:40,620 --> 00:19:41,120 Right. 345 00:19:41,120 --> 00:19:43,235 I mean, you could represent it as a matrix. 346 00:19:43,235 --> 00:19:43,830 Right. 347 00:19:43,830 --> 00:19:47,020 This-- or you could say, well, I hate dictionaries, 348 00:19:47,020 --> 00:19:49,249 I love lists, and that's all I'm going to use 349 00:19:49,249 --> 00:19:50,540 for the rest of my life, right? 350 00:19:50,540 --> 00:19:51,950 Not a good idea. 351 00:19:51,950 --> 00:19:54,710 But if you did that, you could certainly 352 00:19:54,710 --> 00:20:01,080 represent the graphs as a matrix or two dimensional list. 353 00:20:01,080 --> 00:20:04,010 It's called an adjacency matrix representation-- 354 00:20:04,010 --> 00:20:07,610 and I won't write it out-- but, effectively, your rows 355 00:20:07,610 --> 00:20:11,180 are all the nodes, and your columns are all the nodes. 356 00:20:11,180 --> 00:20:16,760 And you have a 1 or a zero in the appropriate location 357 00:20:16,760 --> 00:20:20,540 based on whether there's an edge between the row 358 00:20:20,540 --> 00:20:22,550 node and the column node. 359 00:20:22,550 --> 00:20:25,170 And you can certainly do that. 360 00:20:25,170 --> 00:20:30,890 And it's-- for most cases-- in most cases, 361 00:20:30,890 --> 00:20:35,870 it's a painful representation to deal with. 362 00:20:35,870 --> 00:20:38,071 Graphs are much easier to deal with, especially 363 00:20:38,071 --> 00:20:39,320 when you want to do traversal. 364 00:20:39,320 --> 00:20:41,340 So we'll stick with a graph structure. 365 00:20:41,340 --> 00:20:42,830 All right. 366 00:20:42,830 --> 00:20:45,020 So let's talk algorithms. 367 00:20:45,020 --> 00:20:47,660 I want to take a slightly different example. 368 00:20:47,660 --> 00:20:51,620 It's similar to what we have here, but-- 369 00:20:51,620 --> 00:20:56,580 and I want to talk about exactly how an algorithm would work. 370 00:20:56,580 --> 00:20:57,650 And we kind of did that. 371 00:20:57,650 --> 00:21:02,090 So, actually, let's run it on this one, 372 00:21:02,090 --> 00:21:05,071 and then I'll write out what the pseudocode for the algorithm 373 00:21:05,071 --> 00:21:05,570 would be. 374 00:21:08,880 --> 00:21:10,920 I'm going to ignore A here. 375 00:21:10,920 --> 00:21:14,430 You can imagine that this particular algorithm would 376 00:21:14,430 --> 00:21:18,305 be run on this degenerate case that corresponds to A, 377 00:21:18,305 --> 00:21:21,810 and you'd end up coloring this red or blue. 378 00:21:21,810 --> 00:21:24,690 So I'm just going to go ahead and color this red. 379 00:21:24,690 --> 00:21:27,690 And I'm not done with my problem, 380 00:21:27,690 --> 00:21:30,450 but I'm done with the particular graph that 381 00:21:30,450 --> 00:21:33,480 corresponds to A, because A can't reach 382 00:21:33,480 --> 00:21:35,264 any other node in the graph. 383 00:21:35,264 --> 00:21:36,930 So you ought to be a little bit careful. 384 00:21:36,930 --> 00:21:38,346 And the code I'm going to show you 385 00:21:38,346 --> 00:21:41,640 would need to be generalized to take into account 386 00:21:41,640 --> 00:21:44,160 this forest of graphs. 387 00:21:44,160 --> 00:21:44,820 OK. 388 00:21:44,820 --> 00:21:46,903 Because there's really a bunch of different graphs 389 00:21:46,903 --> 00:21:49,900 that are disconnected that are part of the overall problem. 390 00:21:49,900 --> 00:21:53,070 But if I start with B, then I get connectivity 391 00:21:53,070 --> 00:21:56,980 to all of the remaining edges, and so I'm good there. 392 00:21:56,980 --> 00:22:00,090 So let me go ahead and color this red. 393 00:22:00,090 --> 00:22:04,500 And so the way we described it, we say, 394 00:22:04,500 --> 00:22:07,440 I'm going to look for the neighbors of B. 395 00:22:07,440 --> 00:22:10,890 And so B is connected to just C in this case. 396 00:22:10,890 --> 00:22:14,280 And when I traverse an edge, what do 397 00:22:14,280 --> 00:22:18,120 I do with respect to the color? 398 00:22:18,120 --> 00:22:19,350 I flip the color. 399 00:22:19,350 --> 00:22:19,950 Right. 400 00:22:19,950 --> 00:22:20,880 I change the color. 401 00:22:20,880 --> 00:22:22,470 There's only two colors so I can think 402 00:22:22,470 --> 00:22:24,270 of it as flipping the color. 403 00:22:24,270 --> 00:22:26,610 So I go and I traverse an edge. 404 00:22:26,610 --> 00:22:28,900 I need to flip the color to-- 405 00:22:28,900 --> 00:22:30,390 to blue, right? 406 00:22:30,390 --> 00:22:35,460 And then I get to C, and when I get to C, 407 00:22:35,460 --> 00:22:38,070 I then start traversing edges. 408 00:22:38,070 --> 00:22:40,500 But when I traverse an edge, I need to flip the color. 409 00:22:40,500 --> 00:22:44,135 So this goes to R. In the case of D, 410 00:22:44,135 --> 00:22:46,320 I can go to two different places, 411 00:22:46,320 --> 00:22:49,290 and so I need to go ahead and traverse to E. 412 00:22:49,290 --> 00:22:50,940 And just for the heck of it, I'm going 413 00:22:50,940 --> 00:22:52,151 to add another edge there. 414 00:22:52,151 --> 00:22:52,650 Right. 415 00:22:52,650 --> 00:22:55,440 Because now you're going to see how-- 416 00:22:55,440 --> 00:22:57,580 the code is going to get a little more complicated 417 00:22:57,580 --> 00:22:59,400 with respect to the termination condition 418 00:22:59,400 --> 00:23:01,230 that I described to you, and the checks 419 00:23:01,230 --> 00:23:04,020 that we need to perform with respect to the fact 420 00:23:04,020 --> 00:23:06,150 that we wanted this graph to be two colorable. 421 00:23:06,150 --> 00:23:07,350 OK. 422 00:23:07,350 --> 00:23:10,820 So when I-- the way-- the way this code is going to work 423 00:23:10,820 --> 00:23:15,300 is I'm going to get to D, and with that color red, 424 00:23:15,300 --> 00:23:17,460 and I'm going to now see for the first time-- this 425 00:23:17,460 --> 00:23:19,500 is an interesting case. 426 00:23:19,500 --> 00:23:22,620 For the first time, I'm going to see that D has two neighbors. 427 00:23:22,620 --> 00:23:23,570 OK. 428 00:23:23,570 --> 00:23:27,310 Now, I need to traverse both of these edges that 429 00:23:27,310 --> 00:23:30,540 correspond to these two neighbors in sequence. 430 00:23:30,540 --> 00:23:32,560 I'm going to pick one and go with that. 431 00:23:32,560 --> 00:23:34,920 And then I'm going to pick the other one, right? 432 00:23:34,920 --> 00:23:39,240 In general, there's two strategies that you can follow. 433 00:23:39,240 --> 00:23:42,480 And one of which is called depth first search, and the other 434 00:23:42,480 --> 00:23:44,190 is called breadth first search. 435 00:23:44,190 --> 00:23:44,970 OK. 436 00:23:44,970 --> 00:23:48,300 So I'm not going to-- you're going to see effectively 437 00:23:48,300 --> 00:23:50,250 a depth first algorithm. 438 00:23:50,250 --> 00:23:55,340 And I'm happy to tell you about breadth first in detail 439 00:23:55,340 --> 00:23:58,632 off line, but I'll mention what the difference is here 440 00:23:58,632 --> 00:24:00,590 so you get a sense of what the differences are. 441 00:24:00,590 --> 00:24:03,090 And they're two fundamental search techniques, 442 00:24:03,090 --> 00:24:04,500 traversal techniques. 443 00:24:04,500 --> 00:24:10,650 And the depth first technique says I'm going to take D, 444 00:24:10,650 --> 00:24:12,810 and I'm going to pick one of its neighbors, 445 00:24:12,810 --> 00:24:15,755 and I'm going to go ahead and say that, effectively, 446 00:24:15,755 --> 00:24:18,990 that that's the only neighbor, and I'm 447 00:24:18,990 --> 00:24:20,730 going to explore everything that I 448 00:24:20,730 --> 00:24:23,130 can get to from that neighbor. 449 00:24:23,130 --> 00:24:25,500 And then once I'm all done and there's some termination 450 00:24:25,500 --> 00:24:28,380 condition that happens, I'm going to come back 451 00:24:28,380 --> 00:24:30,990 and I'm going to look at this other neighbor corresponding 452 00:24:30,990 --> 00:24:31,880 to F. 453 00:24:31,880 --> 00:24:33,790 So-- so what would happen here in depth 454 00:24:33,790 --> 00:24:36,270 first search is the following. 455 00:24:36,270 --> 00:24:40,440 D would go to E, and when I go through an edge, 456 00:24:40,440 --> 00:24:41,921 I need to flip the color. 457 00:24:41,921 --> 00:24:42,420 Right. 458 00:24:42,420 --> 00:24:44,670 So I get a B here. 459 00:24:44,670 --> 00:24:48,210 At this point, unlike what we did 460 00:24:48,210 --> 00:24:52,140 early on when we did this particular example, 461 00:24:52,140 --> 00:24:54,480 or something similar, I-- 462 00:24:54,480 --> 00:24:56,430 what I did was when I saw R here, 463 00:24:56,430 --> 00:25:00,110 I colored F and E both blue. 464 00:25:00,110 --> 00:25:01,360 That's effectively what I did. 465 00:25:01,360 --> 00:25:02,220 Remember that? 466 00:25:02,220 --> 00:25:02,962 Right? 467 00:25:02,962 --> 00:25:04,920 But now I'm actually doing something different. 468 00:25:04,920 --> 00:25:05,420 Right. 469 00:25:05,420 --> 00:25:07,950 This is a different execution corresponding 470 00:25:07,950 --> 00:25:10,230 to depth first search. 471 00:25:10,230 --> 00:25:10,740 Right. 472 00:25:10,740 --> 00:25:12,790 When I looked at all of my neighbors, 473 00:25:12,790 --> 00:25:16,210 including the F case, I remember we had some color for this, 474 00:25:16,210 --> 00:25:18,420 and then we immediately took G, H and I 475 00:25:18,420 --> 00:25:19,640 and we colored them, right? 476 00:25:19,640 --> 00:25:21,040 That is breadth first search. 477 00:25:21,040 --> 00:25:21,540 OK. 478 00:25:21,540 --> 00:25:25,080 That is looking at taking one step in all directions 479 00:25:25,080 --> 00:25:27,330 that you can take and, essentially, it's 480 00:25:27,330 --> 00:25:30,750 a frontier based approach where I'm 481 00:25:30,750 --> 00:25:33,120 taking the frontier of my neighbors 482 00:25:33,120 --> 00:25:36,630 and pushing it outward one step at a time, right? 483 00:25:36,630 --> 00:25:40,170 Contrast that with what we're doing here. 484 00:25:40,170 --> 00:25:44,420 You are going to take this-- 485 00:25:44,420 --> 00:25:46,830 the neighbor E corresponding to D, 486 00:25:46,830 --> 00:25:49,290 and then you're not going to go to F, 487 00:25:49,290 --> 00:25:51,810 you're, in fact, going to go ahead and pick one 488 00:25:51,810 --> 00:25:54,030 of the neighbors of E, right. 489 00:25:54,030 --> 00:25:58,800 And you might even have in your representation E's neighbor 490 00:25:58,800 --> 00:26:01,980 being D. Because, you know, D has E as a neighbor 491 00:26:01,980 --> 00:26:04,410 and so does E having-- 492 00:26:04,410 --> 00:26:05,940 has D as a neighbor. 493 00:26:05,940 --> 00:26:07,320 But you'll say, oh, look, look, I 494 00:26:07,320 --> 00:26:11,460 don't need to go look at D now in my depth first search, 495 00:26:11,460 --> 00:26:13,260 because D's already been colored. 496 00:26:13,260 --> 00:26:13,770 Right. 497 00:26:13,770 --> 00:26:14,920 So you check that. 498 00:26:14,920 --> 00:26:16,920 And then you say, oh, what has not been colored? 499 00:26:16,920 --> 00:26:18,540 I has not been colored. 500 00:26:18,540 --> 00:26:21,120 And when I traverse an edge, I need to flip the color, 501 00:26:21,120 --> 00:26:23,040 and I'm going to go ahead and put R in here. 502 00:26:23,040 --> 00:26:24,240 All right. 503 00:26:24,240 --> 00:26:26,970 And it's not that you even go back to F now 504 00:26:26,970 --> 00:26:29,010 from D. You don't go back to D at this point. 505 00:26:29,010 --> 00:26:33,300 You now look at I and you do another recursion corresponding 506 00:26:33,300 --> 00:26:36,090 to I, and you say, OK, what about I's neighbors. 507 00:26:36,090 --> 00:26:38,400 Well, E may be first, but you already 508 00:26:38,400 --> 00:26:39,870 done with E. I'm going to go ahead 509 00:26:39,870 --> 00:26:42,810 and I'm going to get to F. And you do the flip 510 00:26:42,810 --> 00:26:45,450 and you get B over here, right? 511 00:26:45,450 --> 00:26:50,130 You still don't go-- go back to D. You look at F 512 00:26:50,130 --> 00:26:55,140 and you say I'm going to now look at the neighbors of F, 513 00:26:55,140 --> 00:27:00,150 and maybe you get H. And you say this is R. Then you go back 514 00:27:00,150 --> 00:27:02,700 and, now, for the first time, you're 515 00:27:02,700 --> 00:27:06,360 going to look at exhausting the neighbors of a node 516 00:27:06,360 --> 00:27:09,690 that you've actually reached and you've gone to one neighbor 517 00:27:09,690 --> 00:27:10,410 for. 518 00:27:10,410 --> 00:27:13,530 And so-- so at this point you go and you make this R. 519 00:27:13,530 --> 00:27:16,210 So now you come back and you say, am-- 520 00:27:16,210 --> 00:27:19,580 have I exhausted F's neighbors? 521 00:27:19,580 --> 00:27:22,970 Yes, in the sense that all-- 522 00:27:22,970 --> 00:27:24,800 the neighbors that I needed to look at, 523 00:27:24,800 --> 00:27:27,350 because they didn't have colors, have been exhausted. 524 00:27:27,350 --> 00:27:30,140 And, of course, F had D and I as neighbors. 525 00:27:30,140 --> 00:27:35,090 And they already had colors so I'm cool with that, right? 526 00:27:35,090 --> 00:27:36,050 I don't need to-- 527 00:27:36,050 --> 00:27:37,580 I don't need to touch them. 528 00:27:37,580 --> 00:27:39,950 Now, at this point, I'm popping up 529 00:27:39,950 --> 00:27:43,310 because I've exhausted F's neighbors. 530 00:27:43,310 --> 00:27:45,800 I'm going to go back to where I came from. 531 00:27:45,800 --> 00:27:47,120 How did I get to F? 532 00:27:47,120 --> 00:27:51,480 I did not get to F from D. I actually got to F from I, 533 00:27:51,480 --> 00:27:51,980 right? 534 00:27:51,980 --> 00:27:54,260 So I'm going to go to I. But the fact of the matter 535 00:27:54,260 --> 00:27:59,030 is that I is done because I didn't have to deal with E 536 00:27:59,030 --> 00:27:59,780 and I've already-- 537 00:27:59,780 --> 00:28:01,560 I'm already done with that. 538 00:28:01,560 --> 00:28:04,670 Then I go back to E, same thing, right? 539 00:28:04,670 --> 00:28:06,890 Then, finally, I get back to D, and I say, 540 00:28:06,890 --> 00:28:10,730 oh, now I need to go look at F, and I go and I say, 541 00:28:10,730 --> 00:28:14,420 oh, F is already colored so, therefore, I'm done. 542 00:28:14,420 --> 00:28:16,610 This is the simplest representation 543 00:28:16,610 --> 00:28:22,640 that I can think of for a graph that's also very efficient. 544 00:28:22,640 --> 00:28:26,870 So I've messed with this graph quite a bit, 545 00:28:26,870 --> 00:28:30,860 so I want to claim that that dictionary representation that 546 00:28:30,860 --> 00:28:33,067 says graph equals open curly brackets, 547 00:28:33,067 --> 00:28:35,650 and then eventually close curly brackets, corresponds to that, 548 00:28:35,650 --> 00:28:38,430 but it's kind of roughly corresponds to that. 549 00:28:38,430 --> 00:28:43,340 And I can certainly write out any graph representation 550 00:28:43,340 --> 00:28:49,040 in Python for any topological representation 551 00:28:49,040 --> 00:28:50,150 that you give me. 552 00:28:50,150 --> 00:28:53,190 But if you look at what's up there, 553 00:28:53,190 --> 00:28:56,240 the important thing is I want to show you-- 554 00:28:56,240 --> 00:29:02,380 or tell you about the constituents of this graph. 555 00:29:02,380 --> 00:29:05,440 So graph is a dictionary, OK. 556 00:29:05,440 --> 00:29:10,665 A dictionary is a set of key value pairs. 557 00:29:19,220 --> 00:29:22,840 You represent sets in Python using curly brackets. 558 00:29:22,840 --> 00:29:23,540 Right. 559 00:29:23,540 --> 00:29:27,590 And each of the key value pairs is represented 560 00:29:27,590 --> 00:29:32,120 using some key colon val. 561 00:29:32,120 --> 00:29:33,950 And you see a set of key value pairs, 562 00:29:33,950 --> 00:29:36,240 because you see these commas between them, 563 00:29:36,240 --> 00:29:39,040 and so what you see here is the key. 564 00:29:39,040 --> 00:29:43,910 And the keys could be strings, they could be tuples, 565 00:29:43,910 --> 00:29:46,910 you can have many possibilities for keys. 566 00:29:46,910 --> 00:29:48,690 And the key comes first. 567 00:29:48,690 --> 00:29:52,840 And in this case, the key is the string B. OK. 568 00:29:52,840 --> 00:29:57,680 And so that represents the name of the node B, 569 00:29:57,680 --> 00:30:06,030 and the value is usually a list. 570 00:30:06,030 --> 00:30:08,090 And in this case, you have a list 571 00:30:08,090 --> 00:30:11,330 that has a single entry in it because B only has 572 00:30:11,330 --> 00:30:15,260 one edge that goes to C. Right. 573 00:30:15,260 --> 00:30:19,160 And so a more interesting case, as you can see up there, 574 00:30:19,160 --> 00:30:25,496 is D. And D connects to C, F and E. And so you see D-- 575 00:30:25,496 --> 00:30:27,060 see E and F. Right. 576 00:30:27,060 --> 00:30:29,450 So that's exactly what the point here is. 577 00:30:29,450 --> 00:30:30,020 Right. 578 00:30:30,020 --> 00:30:32,210 This algorithm would run differently 579 00:30:32,210 --> 00:30:36,500 if you had a representation that was equivalent 580 00:30:36,500 --> 00:30:38,780 from a topological standpoint, because there's 581 00:30:38,780 --> 00:30:41,600 no order in the topology. 582 00:30:41,600 --> 00:30:46,280 But I chose C, E, F. I-- you know, it got typed somewhere, 583 00:30:46,280 --> 00:30:48,980 C, E, F, and so the order of neighbors 584 00:30:48,980 --> 00:30:51,380 is C followed by E followed by F. 585 00:30:51,380 --> 00:30:54,500 Now, that is if you took this list of neighbors 586 00:30:54,500 --> 00:30:58,760 and you went from 0, 1, 2, in terms of indices of that list. 587 00:30:58,760 --> 00:31:01,800 There's nothing that's stopping you from going 2, 1, zero. 588 00:31:01,800 --> 00:31:04,790 In which case, you would go F, E, C. Right. 589 00:31:04,790 --> 00:31:11,120 Or you could do some crazy, random ordering for the list 590 00:31:11,120 --> 00:31:11,660 itself. 591 00:31:11,660 --> 00:31:11,870 Right. 592 00:31:11,870 --> 00:31:13,300 But it's all entirely up to you. 593 00:31:13,300 --> 00:31:13,800 Right. 594 00:31:13,800 --> 00:31:14,790 It is deterministic. 595 00:31:14,790 --> 00:31:16,020 It's entirely up to you. 596 00:31:16,020 --> 00:31:21,200 But, now, you see how the order of the values that corresponds 597 00:31:21,200 --> 00:31:25,160 to these lists that give you the neighbors for every node 598 00:31:25,160 --> 00:31:27,180 affects the execution of the algorithm. 599 00:31:27,180 --> 00:31:27,860 Right. 600 00:31:27,860 --> 00:31:31,050 Now, you do not want the result of the algorithm 601 00:31:31,050 --> 00:31:34,220 yes or no, this graph is bipartite or not, 602 00:31:34,220 --> 00:31:36,630 to be affected by the order that you see there. 603 00:31:36,630 --> 00:31:37,130 Right. 604 00:31:37,130 --> 00:31:40,190 Because when I draw a graph like this, I mean, 605 00:31:40,190 --> 00:31:42,530 this graph is effectively something 606 00:31:42,530 --> 00:31:44,090 that doesn't have order. 607 00:31:44,090 --> 00:31:48,230 You can't really say anything about the order of G, 608 00:31:48,230 --> 00:31:51,110 H and I in relation to F. I mean, they're-- 609 00:31:51,110 --> 00:31:54,340 well, that one is to the left of it, they're all-- 610 00:31:54,340 --> 00:31:55,730 two of them are at the bottom. 611 00:31:55,730 --> 00:31:58,640 But that's not what this is about. 612 00:31:58,640 --> 00:32:02,330 And so, obviously, that graph, regardless of whether I-- 613 00:32:02,330 --> 00:32:08,590 I drew it like this or I-- you know, I drew it like that, 614 00:32:08,590 --> 00:32:10,600 should be bipartite. 615 00:32:10,600 --> 00:32:12,180 Both of those graphs that I-- 616 00:32:12,180 --> 00:32:14,870 that correspond to H and G with their names 617 00:32:14,870 --> 00:32:18,100 flipped, are either bipartite or not bipartite. 618 00:32:18,100 --> 00:32:18,600 Right. 619 00:32:18,600 --> 00:32:22,170 So you absolutely cannot have the algorithm being affected 620 00:32:22,170 --> 00:32:26,520 by the order in which you see C, E, F or what have you. 621 00:32:26,520 --> 00:32:28,840 That make sense? 622 00:32:28,840 --> 00:32:33,090 So you can do a lot of operations on dictionaries. 623 00:32:33,090 --> 00:32:35,460 It's probably something that you want 624 00:32:35,460 --> 00:32:40,090 to look at by looking at the code that we have here 625 00:32:40,090 --> 00:32:48,060 and looking at the code from graph analysis algorithms, 626 00:32:48,060 --> 00:32:50,940 and I'm happy to point you to other literature. 627 00:32:50,940 --> 00:32:56,220 But the way you access a dictionary is-- 628 00:32:56,220 --> 00:32:58,270 looks a lot like accessing a list. 629 00:32:58,270 --> 00:33:01,720 So you can say something like graph A, 630 00:33:01,720 --> 00:33:03,880 and you say something like graph A, 631 00:33:03,880 --> 00:33:08,950 if A is not a key in the graph, it would give you an error. 632 00:33:12,820 --> 00:33:20,160 But you can certainly get values back, 633 00:33:20,160 --> 00:33:21,610 and you can also assign values. 634 00:33:21,610 --> 00:33:29,950 So graph A, B would give-- it would give you this list C, 635 00:33:29,950 --> 00:33:32,530 and you can go off and you can say something like graph A, 636 00:33:32,530 --> 00:33:34,400 B dot append-- 637 00:33:38,970 --> 00:33:42,840 --and you can say D. And if you did that, if you did graph A, 638 00:33:42,840 --> 00:33:46,260 B dot append D, then that's effectively 639 00:33:46,260 --> 00:33:51,910 taking this and adding D to it. 640 00:33:51,910 --> 00:33:54,220 So you can mutate the graph if you wanted. 641 00:33:54,220 --> 00:33:56,320 We don't have to do that in our code 642 00:33:56,320 --> 00:33:58,780 for bipartite, graph checking, because we are not 643 00:33:58,780 --> 00:34:02,110 mutating the graph, we're just traversing the graph. 644 00:34:02,110 --> 00:34:03,740 But you could certainly do that. 645 00:34:03,740 --> 00:34:06,830 So the dictionaries are a pretty cool representation. 646 00:34:06,830 --> 00:34:10,389 Encourage you to learn about them. 647 00:34:10,389 --> 00:34:14,949 And they're useful in many instances. 648 00:34:14,949 --> 00:34:18,159 Clearly, they replace lists because you can certainly 649 00:34:18,159 --> 00:34:21,760 have keys as integers, right? 650 00:34:21,760 --> 00:34:24,699 You can also have negative numbers as keys. 651 00:34:24,699 --> 00:34:26,889 There's nothing that's stopping you from doing that. 652 00:34:26,889 --> 00:34:29,530 And you don't have to represent the negative number 653 00:34:29,530 --> 00:34:30,940 as a string. 654 00:34:30,940 --> 00:34:33,210 I mean, you could just have keys that are-- 655 00:34:33,210 --> 00:34:38,840 that go from minus 22 to 27, what have you. 656 00:34:38,840 --> 00:34:41,380 So, hopefully, you have some sense 657 00:34:41,380 --> 00:34:43,210 of what this code is going to look like. 658 00:34:43,210 --> 00:34:45,250 Both from a standpoint of the algorithm, which 659 00:34:45,250 --> 00:34:48,159 we executed a few times, and from the standpoint 660 00:34:48,159 --> 00:34:51,620 of the structure, the representation of the graph. 661 00:34:51,620 --> 00:34:56,139 So let's take a look at about 10 lines of code 662 00:34:56,139 --> 00:34:59,350 that corresponds to bipartite graph coloring. 663 00:34:59,350 --> 00:35:01,090 So it fits on a screen. 664 00:35:01,090 --> 00:35:01,870 OK. 665 00:35:01,870 --> 00:35:04,240 And so this is a pretty tight code. 666 00:35:04,240 --> 00:35:07,000 It does exactly what we want it to do 667 00:35:07,000 --> 00:35:09,700 in the sense of it's going to determine whether a graph is 668 00:35:09,700 --> 00:35:11,230 bipartite or not. 669 00:35:11,230 --> 00:35:14,770 And it has a bunch of arguments. 670 00:35:14,770 --> 00:35:17,290 A graph is what you imagine it to be. 671 00:35:17,290 --> 00:35:19,000 It's the input graph. 672 00:35:19,000 --> 00:35:21,580 We have to start from somewhere. 673 00:35:21,580 --> 00:35:24,950 This graph has a list of key value pairs. 674 00:35:24,950 --> 00:35:27,370 The keys happen to be the nodes. 675 00:35:27,370 --> 00:35:30,040 You should never depend on the keys being 676 00:35:30,040 --> 00:35:32,350 stored in a particular order. 677 00:35:32,350 --> 00:35:33,490 There's ways of saying-- 678 00:35:33,490 --> 00:35:35,531 you know, you can say things like graph dot keys. 679 00:35:40,750 --> 00:35:46,540 And this is going to give you back a list of keys. 680 00:35:46,540 --> 00:35:48,755 And it's possible that when you say graph dot 681 00:35:48,755 --> 00:35:50,530 keys, at one point in the program, 682 00:35:50,530 --> 00:35:52,889 you get the keys in a particular order. 683 00:35:52,889 --> 00:35:55,180 And when you say it at a different part of the program, 684 00:35:55,180 --> 00:35:56,890 you get the keys in a different order. 685 00:35:56,890 --> 00:35:57,880 OK. 686 00:35:57,880 --> 00:36:00,000 But all-- the keys won't change. 687 00:36:00,000 --> 00:36:01,510 If there's no bugs in your program, 688 00:36:01,510 --> 00:36:03,400 you'll get the same set of keys, but they 689 00:36:03,400 --> 00:36:04,960 may be in different order. 690 00:36:04,960 --> 00:36:11,230 So you obviously want to start with some node in the graph, 691 00:36:11,230 --> 00:36:13,540 and you're going to color it with a particular color, 692 00:36:13,540 --> 00:36:14,500 color it red. 693 00:36:14,500 --> 00:36:17,830 I think I had shaded and hatched here, so sha stands for shaded, 694 00:36:17,830 --> 00:36:19,720 and hat stands for hatched. 695 00:36:19,720 --> 00:36:23,370 But you can use what you want. 696 00:36:23,370 --> 00:36:28,300 So if you see the invocation here, bipartite graph color-- 697 00:36:28,300 --> 00:36:30,980 graph three starts with a node. 698 00:36:30,980 --> 00:36:33,970 This is an-- its coloring is a dictionary, 699 00:36:33,970 --> 00:36:37,480 and so we are also representing not only the graph 700 00:36:37,480 --> 00:36:40,510 as a dictionary, but we're also representing the mapping 701 00:36:40,510 --> 00:36:41,380 that we get. 702 00:36:41,380 --> 00:36:44,170 Namely, the node B was colored with red. 703 00:36:44,170 --> 00:36:47,890 So B is a key in this coloring dictionary. 704 00:36:47,890 --> 00:36:50,810 And R red is-- 705 00:36:50,810 --> 00:36:52,460 is the color that's a value. 706 00:36:52,460 --> 00:36:52,960 Right. 707 00:36:52,960 --> 00:36:54,310 So you can represent mappings. 708 00:36:54,310 --> 00:36:55,570 Key values or mappings. 709 00:36:55,570 --> 00:36:56,200 Right. 710 00:36:56,200 --> 00:37:00,165 So the coloring of a node is also a dictionary. 711 00:37:00,165 --> 00:37:01,790 And so that's essentially what we have. 712 00:37:01,790 --> 00:37:02,956 So I'm going to start with-- 713 00:37:02,956 --> 00:37:06,220 none of the nodes are colored, so that's why this is empty, 714 00:37:06,220 --> 00:37:07,900 and I'm going to start with A, and I'm 715 00:37:07,900 --> 00:37:10,255 going to start with the color shaded, which means that A 716 00:37:10,255 --> 00:37:11,950 is going to be colored shaded. 717 00:37:11,950 --> 00:37:13,330 Or A is going to be shaded. 718 00:37:13,330 --> 00:37:14,080 OK. 719 00:37:14,080 --> 00:37:18,460 And this is going to return true or false depending 720 00:37:18,460 --> 00:37:22,070 on whether the graph is bipartite or not. 721 00:37:22,070 --> 00:37:24,760 And if it's true, then I'm going to get 722 00:37:24,760 --> 00:37:28,870 something interesting with respect to the mapping of nodes 723 00:37:28,870 --> 00:37:29,830 to colors. 724 00:37:29,830 --> 00:37:32,200 That's my dictionary coloring. 725 00:37:32,200 --> 00:37:34,300 And, otherwise, I get false back, 726 00:37:34,300 --> 00:37:35,470 which an empty dictionary. 727 00:37:35,470 --> 00:37:37,870 Because when I have something that's false, I mean, 728 00:37:37,870 --> 00:37:42,350 you could imagine saying, well, there's a problem case here. 729 00:37:42,350 --> 00:37:45,160 You can color all of these different nodes, 730 00:37:45,160 --> 00:37:48,520 but I'm kind of stuck here because of that five cycle. 731 00:37:48,520 --> 00:37:53,260 But that's kind of indeterminate in terms 732 00:37:53,260 --> 00:37:55,760 of what the colors need to be. 733 00:37:55,760 --> 00:37:58,440 And so-- unless you were actually going to go off 734 00:37:58,440 --> 00:38:01,420 and mutate the graph and remove a node and-- 735 00:38:01,420 --> 00:38:04,240 and say this is the friend you want to dump today, 736 00:38:04,240 --> 00:38:08,265 and then the rest of them are going to be invited for dinner. 737 00:38:08,265 --> 00:38:09,640 In that case, you could obviously 738 00:38:09,640 --> 00:38:11,800 return a coloring dictionary, even 739 00:38:11,800 --> 00:38:13,240 in this case of the graph-- 740 00:38:13,240 --> 00:38:15,280 original graph not being bipartite. 741 00:38:15,280 --> 00:38:18,400 But most of the time you're probably in a situation 742 00:38:18,400 --> 00:38:21,580 where if it's not bipartite, you don't return anything other 743 00:38:21,580 --> 00:38:22,510 than false. 744 00:38:22,510 --> 00:38:23,470 All right. 745 00:38:23,470 --> 00:38:28,210 So let's take a look at what each of these things 746 00:38:28,210 --> 00:38:31,810 do, and then you'll also get a sense of how we manipulate 747 00:38:31,810 --> 00:38:33,310 dictionary structures. 748 00:38:33,310 --> 00:38:37,150 So I'm just going to explain very quickly each line of code 749 00:38:37,150 --> 00:38:38,000 here. 750 00:38:38,000 --> 00:38:42,790 So this pair of lines of-- this pair of lines of code, 751 00:38:42,790 --> 00:38:46,460 essentially, say something like, well, 752 00:38:46,460 --> 00:38:49,000 if you've given me a starting node, 753 00:38:49,000 --> 00:38:50,717 it's just a check on the input. 754 00:38:50,717 --> 00:38:52,300 The starting node is not in the graph, 755 00:38:52,300 --> 00:38:54,951 it's not a key in the graph, then 756 00:38:54,951 --> 00:38:56,200 I'm throwing up my hands here. 757 00:38:56,200 --> 00:38:57,760 This is not a graph. 758 00:38:57,760 --> 00:38:59,110 It's not a bipartite graph. 759 00:38:59,110 --> 00:39:00,550 I can give you a coloring, right. 760 00:39:00,550 --> 00:39:01,810 So easy check. 761 00:39:01,810 --> 00:39:03,880 Not much there. 762 00:39:03,880 --> 00:39:05,950 This is an interesting check. 763 00:39:05,950 --> 00:39:07,780 This, essentially, is going to check 764 00:39:07,780 --> 00:39:12,490 to see whether the particular node that you have, 765 00:39:12,490 --> 00:39:14,600 this is going to be done recursively. 766 00:39:14,600 --> 00:39:17,140 So anytime you arrive at a node, you 767 00:39:17,140 --> 00:39:20,170 have to check whether there's already a color there or not. 768 00:39:20,170 --> 00:39:25,120 If there's no color, then you move forward, and you color it, 769 00:39:25,120 --> 00:39:26,800 and you also move forward in the sense 770 00:39:26,800 --> 00:39:29,407 that you'll probably go ahead and if it has neighbors, 771 00:39:29,407 --> 00:39:30,740 you will traverse the neighbors. 772 00:39:30,740 --> 00:39:31,450 Right. 773 00:39:31,450 --> 00:39:34,750 But if it has a color, if it's already in coloring, 774 00:39:34,750 --> 00:39:36,320 that means it already has a color. 775 00:39:36,320 --> 00:39:36,820 Right. 776 00:39:36,820 --> 00:39:40,480 Because the keys that correspond to the coloring dictionary 777 00:39:40,480 --> 00:39:44,440 are exactly the same in the sense that they're graph nodes 778 00:39:44,440 --> 00:39:46,300 and they're also in the graph dictionary. 779 00:39:46,300 --> 00:39:47,170 Right. 780 00:39:47,170 --> 00:39:49,460 The mappings are, of course, completely different, 781 00:39:49,460 --> 00:39:52,195 and the coloring dictionary is being grown as we speak, 782 00:39:52,195 --> 00:39:53,920 or as we execute. 783 00:39:53,920 --> 00:39:57,220 But the graph dictionary is actually not mutated. 784 00:39:57,220 --> 00:39:58,300 It's static. 785 00:39:58,300 --> 00:39:59,200 OK. 786 00:39:59,200 --> 00:40:03,580 And so this check here says that I'm going to go ahead, 787 00:40:03,580 --> 00:40:05,870 and if it's not in coloring, oh, that's great. 788 00:40:05,870 --> 00:40:07,870 I'm going to go ahead and whatever color I have, 789 00:40:07,870 --> 00:40:10,030 I'm going to go ahead and color it with that. 790 00:40:10,030 --> 00:40:12,760 That's what coloring start equals color does. 791 00:40:12,760 --> 00:40:14,090 It just colors the node. 792 00:40:14,090 --> 00:40:14,590 OK. 793 00:40:14,590 --> 00:40:18,970 And then that effectively is adding the key value pair 794 00:40:18,970 --> 00:40:22,530 start comma color to the coloring dictionary. 795 00:40:22,530 --> 00:40:23,950 That's what it does. 796 00:40:23,950 --> 00:40:26,750 Otherwise-- well, I got two cases here. 797 00:40:26,750 --> 00:40:27,250 Right. 798 00:40:27,250 --> 00:40:30,490 This thing has already been colored, but I have two cases. 799 00:40:30,490 --> 00:40:33,910 I want to color it with something different from what 800 00:40:33,910 --> 00:40:35,320 it's already been colored. 801 00:40:35,320 --> 00:40:37,180 That's a problem. 802 00:40:37,180 --> 00:40:37,970 That's a problem. 803 00:40:37,970 --> 00:40:39,760 That's exactly when we get a five cycle 804 00:40:39,760 --> 00:40:41,410 and we throw up our hands. 805 00:40:41,410 --> 00:40:42,490 So we're done here. 806 00:40:42,490 --> 00:40:46,870 We just say doesn't matter what we've colored so far, 807 00:40:46,870 --> 00:40:48,150 it's all garbage. 808 00:40:48,150 --> 00:40:51,160 You know, this thing can't be colored with two colors given 809 00:40:51,160 --> 00:40:52,990 the constraints I have, so I'm just 810 00:40:52,990 --> 00:40:55,630 going to return false and an empty dictionary. 811 00:40:55,630 --> 00:40:59,030 So anything that coloring had in it, I mean, is gone. 812 00:40:59,030 --> 00:40:59,530 Right. 813 00:40:59,530 --> 00:41:02,330 Because it's bogus. 814 00:41:02,330 --> 00:41:04,630 Otherwise, this recursion would say, 815 00:41:04,630 --> 00:41:09,850 oh, well, I'm going to return true for this thing here, 816 00:41:09,850 --> 00:41:12,070 and I'm going to-- 817 00:41:12,070 --> 00:41:16,330 it has been colored, which means that, you know, I haven't-- 818 00:41:16,330 --> 00:41:18,032 I don't want to do any more work on it. 819 00:41:18,032 --> 00:41:19,240 I mean, I got this node here. 820 00:41:19,240 --> 00:41:20,781 It's already-- it was already colored 821 00:41:20,781 --> 00:41:22,360 and was consistently colored. 822 00:41:22,360 --> 00:41:24,880 So if I don't want to get into infinite loops, 823 00:41:24,880 --> 00:41:27,910 I better not, you know, start traversing nodes from this node 824 00:41:27,910 --> 00:41:29,691 because I've already seen it before. 825 00:41:29,691 --> 00:41:30,190 All right. 826 00:41:30,190 --> 00:41:33,190 So the fact that it's already colored correctly 827 00:41:33,190 --> 00:41:34,960 is a termination condition. 828 00:41:34,960 --> 00:41:36,470 This is important. 829 00:41:36,470 --> 00:41:39,820 That says that I don't want to keep repeating myself, 830 00:41:39,820 --> 00:41:42,395 that is like going through the cycle over and over. 831 00:41:42,395 --> 00:41:42,895 Right. 832 00:41:42,895 --> 00:41:44,440 If you didn't have that, right? 833 00:41:44,440 --> 00:41:45,530 That make sense? 834 00:41:45,530 --> 00:41:46,450 Yep. 835 00:41:46,450 --> 00:41:48,670 That's important. 836 00:41:48,670 --> 00:41:52,250 So, now-- well, this is a flip. 837 00:41:52,250 --> 00:41:55,670 So there's no recursion, there's no procedure calls here, 838 00:41:55,670 --> 00:41:57,650 this is just flipping the color. 839 00:41:57,650 --> 00:41:58,860 That make sense? 840 00:41:58,860 --> 00:42:03,110 So, now, the last part, which is the part where I'm actually 841 00:42:03,110 --> 00:42:08,300 doing depth first search is the part which says, OK, 842 00:42:08,300 --> 00:42:14,900 I got to the point now where I'm-- essentially, 843 00:42:14,900 --> 00:42:16,640 haven't done any returns here. 844 00:42:16,640 --> 00:42:17,880 Right. 845 00:42:17,880 --> 00:42:21,810 I've colored this with color, and I've flipped the color. 846 00:42:21,810 --> 00:42:22,310 Right. 847 00:42:22,310 --> 00:42:24,560 So these two lines are executed. 848 00:42:24,560 --> 00:42:26,180 No returns. 849 00:42:26,180 --> 00:42:27,710 These lines are executed. 850 00:42:27,710 --> 00:42:33,429 And, now, I have clearly already colored start 851 00:42:33,429 --> 00:42:34,970 and I flipped the color and I'm going 852 00:42:34,970 --> 00:42:37,220 to go ahead and make the recursive call corresponding 853 00:42:37,220 --> 00:42:43,520 to the neighbors of start, and all 854 00:42:43,520 --> 00:42:45,620 I have to do to look at the neighbors of start 855 00:42:45,620 --> 00:42:47,450 is to return the list corresponding 856 00:42:47,450 --> 00:42:49,510 to the value of graph start. 857 00:42:49,510 --> 00:42:52,370 Remember, I said, graph A or graph start 858 00:42:52,370 --> 00:42:53,930 is going to give you this-- 859 00:42:53,930 --> 00:42:57,800 this list, and I can go ahead and append to it and-- 860 00:42:57,800 --> 00:43:00,495 I'm not going to mutate, but I could have done that. 861 00:43:00,495 --> 00:43:02,120 And so that is going to give me my list 862 00:43:02,120 --> 00:43:03,911 and I'm just going to go through, enumerate 863 00:43:03,911 --> 00:43:08,672 that list in whatever order that it came to me, and start with-- 864 00:43:08,672 --> 00:43:10,130 I'm going to call the first element 865 00:43:10,130 --> 00:43:13,970 vertex, because that's also a vertex or a node synonymous. 866 00:43:13,970 --> 00:43:17,330 And I'm going to send in vertex here, graph stays the same, 867 00:43:17,330 --> 00:43:18,710 vertex is the same. 868 00:43:18,710 --> 00:43:21,451 I've modified colorings, so I want to pass that over. 869 00:43:21,451 --> 00:43:23,450 And, obviously, I'm going to pass new color here 870 00:43:23,450 --> 00:43:24,740 because I've done the flip. 871 00:43:24,740 --> 00:43:25,610 Right. 872 00:43:25,610 --> 00:43:27,140 And if I ever-- 873 00:43:27,140 --> 00:43:29,390 I get something that's false, that 874 00:43:29,390 --> 00:43:33,505 means I've found an odd cycle and I return false. 875 00:43:33,505 --> 00:43:34,880 And then if everything works out, 876 00:43:34,880 --> 00:43:36,570 I return true in the coloring. 877 00:43:36,570 --> 00:43:37,620 OK. 878 00:43:37,620 --> 00:43:41,970 So if I go ahead and run that, if my machine hasn't gone 879 00:43:41,970 --> 00:43:45,120 to sleep, doesn't do very much. 880 00:43:45,120 --> 00:43:49,910 You know, the first graph, it was not colorable. 881 00:43:49,910 --> 00:43:52,710 You can check these results by yourself. 882 00:43:52,710 --> 00:43:54,380 But this is more-- 883 00:43:54,380 --> 00:43:56,250 the reason I'm putting this up is 884 00:43:56,250 --> 00:44:00,300 to give you a sense of what the coloring dictionary looks like. 885 00:44:00,300 --> 00:44:03,850 It's just so you get some more exposure to these things. 886 00:44:03,850 --> 00:44:07,020 So in this case you get a non-empty coloring dictionary 887 00:44:07,020 --> 00:44:08,110 for the second run. 888 00:44:08,110 --> 00:44:10,650 So I ran it four times on four different graphs. 889 00:44:10,650 --> 00:44:12,540 You get a non-empty coloring dictionary. 890 00:44:12,540 --> 00:44:13,320 It's true. 891 00:44:13,320 --> 00:44:14,870 The graph is bipartite. 892 00:44:14,870 --> 00:44:17,670 And notice that the order in which this coloring dictionary 893 00:44:17,670 --> 00:44:18,990 was-- 894 00:44:18,990 --> 00:44:21,750 what was created was certainly a function 895 00:44:21,750 --> 00:44:23,920 of the execution of the algorithm. 896 00:44:23,920 --> 00:44:27,810 But this order might actually change 897 00:44:27,810 --> 00:44:29,280 if I keep running this algorithm, 898 00:44:29,280 --> 00:44:32,070 and if my machine had different loads, and so on and so forth. 899 00:44:32,070 --> 00:44:36,540 But you would always get through for any graph representation 900 00:44:36,540 --> 00:44:39,570 that is bipartite or too colorable. 901 00:44:39,570 --> 00:44:44,890 But you have no control over whether F hat comes first, 902 00:44:44,890 --> 00:44:46,652 or E hat comes first. 903 00:44:46,652 --> 00:44:47,610 Those could be flipped. 904 00:44:47,610 --> 00:44:48,660 All right. 905 00:44:48,660 --> 00:44:52,880 So never depend on the order of keys in a dictionary. 906 00:44:52,880 --> 00:44:53,760 OK. 907 00:44:53,760 --> 00:44:55,530 But, certainly, the existence of keys 908 00:44:55,530 --> 00:44:58,930 in a dictionary you can-- or the nonexistence you can depend on. 909 00:44:58,930 --> 00:44:59,430 All right. 910 00:44:59,430 --> 00:44:59,929 Good. 911 00:44:59,929 --> 00:45:04,100 So that's really all I had to say. 912 00:45:04,100 --> 00:45:05,097 Any questions? 913 00:45:08,771 --> 00:45:09,270 All right. 914 00:45:09,270 --> 00:45:10,380 Excellent. 915 00:45:10,380 --> 00:45:13,580 I want credit for finishing one minute early.