Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
ultrafilter
Aug 23, 2007

It's okay if you have any questions.


Xerophyte posted:

Looking at issues 17497, 118599 and 28724 in their tracker: this seems to not currently be possible, but going by the discussion in 28724 it's a candidate for maybe 14.10.

Some people in one of the threads worked around it by making sure that each individual executors had a unique tag and then requiring the same tag for each stage of the pipeline to ensure it all ran on the same machine. I don't know Gitlab's build system but presumably that stops you from actually distributing your builds across multiple machines, so sounds like the very bad type of workaround.

I don't know if we're taking advantage of that capability anyway, seeing as everything would have to be copied to a central location for the linker to run. Thanks for the info.

Adbot
ADBOT LOVES YOU

Gin_Rummy
Aug 4, 2007
Is there a way to layer an image or a div on top of another one as a child without disrupting the contents of the parent div? I basically have groups of square divs with centered spans of text inside of them, and occasionally I am using JS to create an image on top of these divs. The CSS seems pretty inconsistent at placing the image where I want it, and on top of that, it always shoves the text out of alignment. Really, it would be perfect if I could just drop my image on top as its own layer, but is that doable?

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

Gin_Rummy posted:

Is there a way to layer an image or a div on top of another one as a child without disrupting the contents of the parent div? I basically have groups of square divs with centered spans of text inside of them, and occasionally I am using JS to create an image on top of these divs. The CSS seems pretty inconsistent at placing the image where I want it, and on top of that, it always shoves the text out of alignment. Really, it would be perfect if I could just drop my image on top as its own layer, but is that doable?

position:relative the div then position:absolute the image?

Gin_Rummy
Aug 4, 2007

pokeyman posted:

position:relative the div then position:absolute the image?

That was my first thought and first action, but it seemed to treat my image as a child of the page itself… so an image at 50% width is like half the screen, when I really want it to be a fiftieth.

barkbell
Apr 14, 2006

woof
did you set position relative on the parent

Batterypowered7
Aug 8, 2009

The mist that chills you keeps me warm.

I've been out of college for a while now but decided to take some graduate level courses because my employer is covering 100% of the costs. I'm taking an algorithms course and I'm ashamed to admit that it's kicking my rear end way harder than I expected it to. Would this be the place to ask for some help with an assignment question or is that sort of thing frowned upon? I suspect the solution is much easier than I expect but I'm honestly stumped and could use some help.

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...

Batterypowered7 posted:

I've been out of college for a while now but decided to take some graduate level courses because my employer is covering 100% of the costs. I'm taking an algorithms course and I'm ashamed to admit that it's kicking my rear end way harder than I expected it to. Would this be the place to ask for some help with an assignment question or is that sort of thing frowned upon? I suspect the solution is much easier than I expect but I'm honestly stumped and could use some help.

:justpost:

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

Batterypowered7 posted:

I've been out of college for a while now but decided to take some graduate level courses because my employer is covering 100% of the costs. I'm taking an algorithms course and I'm ashamed to admit that it's kicking my rear end way harder than I expected it to. Would this be the place to ask for some help with an assignment question or is that sort of thing frowned upon? I suspect the solution is much easier than I expect but I'm honestly stumped and could use some help.

It's good to be upfront about it being schoolwork so people can tailor their answers, but yeah fire away!

ultrafilter
Aug 23, 2007

It's okay if you have any questions.


Tell us what you've tried and we can give more specific hints.

Boba Pearl
Dec 27, 2019

by Athanatos
I have a website and it's garbage, and every second writing html, css, php, or javascript is bringing me an inch closer to ventilating my own skull. I thought wordpress would make things easier, but instead it makes things juuuust easy enough to create something that looks like poo poo.

https://bobapearlessence.com/
https://bobapearlescence.com/

At the bottom of this page is a "series" box that I pay 200$ a year for, because I don't know how to do what I need to do (write a script that generates first, next, previous, last) buttons.

https://bobapearlessence.com/42-2/

Whenever I use the thing, it makes the buttons line up like this:



I want them to go left to right and be buttons. The thing is, I don't know which part of the code controls that, and when I e-mailed the company I paid for the plugin, they just said it was planned in a future update.

Honestly, I don't want to pay this company every year, 200$, to put buttons on my web comic. I don't know where to go to teach me what I need to know.

Can you point me to where I could find the information I need?

Alternatively, how much do you think it would cost just to pay someone one off to make me the code so I don't have to pay this company every year, 200$? I'm planning to do comics for the next few years, and like, next year I'll have given them 400$, and there has to be a point where I break even just paying a guy to set it up. Or teach me tbh.

Batterypowered7
Aug 8, 2009

The mist that chills you keeps me warm.


pokeyman posted:

It's good to be upfront about it being schoolwork so people can tailor their answers, but yeah fire away!

ultrafilter posted:

Tell us what you've tried and we can give more specific hints.

In certain island of the Caribbean there are N cities, numbered from 1 to N . For each ordered pair of cities (u, v) you know the cost c[u][v] > 0 of flying directly from u to v. In particular, there is a flight between every pair of cities. Each such flight takes one day and flight costs are not necessarily symmetric. Suppose you are in city u and you want to get to city v. You would like to use this opportunity to obtain a frequent flyer status. In order to get the status, you have to travel on at least minDays consecutive days. What is the minimum total cost c(u, v) of a flight schedule that gets you from u to v in at least minDays days?

Design a dynamic programming to solve this problem. Assume you can access c[x][y] for any pair x, y in constant time. You are also given N, u, v and minDays ≤ N

Hint: one way to solve this problem is using dynamic states similar to those on Bellman-Ford’s algorithm.

(a) Define the entries of your table in words. E.g., T (i) or T (i, j) is ....
(b) State recurrence for entries of table in terms of smaller subproblems.
(c) Write pseudocode for your algorithm to solve this problem.
(d) Analyze the running time of your algorithm.
-----

I understand that this is a variation of a shortest path problem. Travel from one city to itself is possible, the cost > 0, and takes one day, and the TAs have clarified that minDays ≥ 1. All cities are connected to each other, so cycles are possible. I'm having trouble visualizing how I'm supposed to plot the path with the lowest weight (cost) that takes minDays ≤ numEdges ≤ N.

E:

My biggest concern is not just having a solution and understanding it, but getting behind the thought process that allows one to arrive at the solution to begin with.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
The problem here explicitly tells you to use dynamic programming, so that's probably where you want to start. Dynamic programming is a specific algorithms technique where you essentially build a table encompassing the entire solution space for a subproblem, use the information in that table to make a new table encompassing the entire solution space for a slightly larger subproblem, and so on until you've built up to and solved the original problem. Keep that table of the entire solution space in mind when you're considering the problem - in a schoolwork setting like this, the reason they're mentioning it is because it's key to solving the problem.

The key here is all about how you break it down into subproblems. Crucially, you want to break it down in a way that having the entire solution space for a subproblem makes it easier (ideally, nearly trivial) to solve the full problem.

So, let's look at the various elements of our problem and see which ones we could conceivably make smaller:

N - While we could make the number of cities smaller and then solve the reduced problem, it's difficult to see how that smaller solution would be useful for solving the full problem.
u, v - While we could change the cities we're looking at, doing so doesn't really make the problem "smaller" in any way. Having this solution also isn't going to help us solve the original problem.
minDays - We're out of other things to try, so hopefully this is it. Can you see how having a table of solutions for (minDays - 1) could be used to solve the full problem?

KillHour
Oct 28, 2007


Boba Pearl posted:

I have a website and it's garbage, and every second writing html, css, php, or javascript is bringing me an inch closer to ventilating my own skull. I thought wordpress would make things easier, but instead it makes things juuuust easy enough to create something that looks like poo poo.

https://bobapearlessence.com/
https://bobapearlescence.com/

At the bottom of this page is a "series" box that I pay 200$ a year for, because I don't know how to do what I need to do (write a script that generates first, next, previous, last) buttons.

https://bobapearlessence.com/42-2/

Whenever I use the thing, it makes the buttons line up like this:



I want them to go left to right and be buttons. The thing is, I don't know which part of the code controls that, and when I e-mailed the company I paid for the plugin, they just said it was planned in a future update.

Honestly, I don't want to pay this company every year, 200$, to put buttons on my web comic. I don't know where to go to teach me what I need to know.

Can you point me to where I could find the information I need?

Alternatively, how much do you think it would cost just to pay someone one off to make me the code so I don't have to pay this company every year, 200$? I'm planning to do comics for the next few years, and like, next year I'll have given them 400$, and there has to be a point where I break even just paying a guy to set it up. Or teach me tbh.



Holy poo poo you're getting ripped off. I'm not a web / front end developer, but this is for sure something you could either pay someone a modest amount of money to do or figure out yourself in a few days of futzing with it.

First, making a button: The way to make a link look like a button is to stick in an anchor tag with CSS styling made to look like a button. Here's a website with some examples of cool looking buttons that are links: https://fdossena.com/index.php?p=html5cool/buttons/i.frag

I spent 15 minutes futzing around with CSS in the browser to give an example of what you could do just with styling (and your style sheets could probably use a once-over by a developer because they're a bit of a mess, no offense).



Now for your expensive plugin problem. The "hard" part is writing a small piece of JS to figure out what the correct link is and replace the href field (the thing that tells the link where to go) with the correct destination. This isn't actually hard but I can't tell you how to do it without some digging because it depends on how your site is laid out.

KillHour
Oct 28, 2007


Jabor posted:

The problem here explicitly tells you to use dynamic programming, so that's probably where you want to start. Dynamic programming is a specific algorithms technique where you essentially build a table encompassing the entire solution space for a subproblem, use the information in that table to make a new table encompassing the entire solution space for a slightly larger subproblem, and so on until you've built up to and solved the original problem. Keep that table of the entire solution space in mind when you're considering the problem - in a schoolwork setting like this, the reason they're mentioning it is because it's key to solving the problem.

The key here is all about how you break it down into subproblems. Crucially, you want to break it down in a way that having the entire solution space for a subproblem makes it easier (ideally, nearly trivial) to solve the full problem.

So, let's look at the various elements of our problem and see which ones we could conceivably make smaller:

N - While we could make the number of cities smaller and then solve the reduced problem, it's difficult to see how that smaller solution would be useful for solving the full problem.
u, v - While we could change the cities we're looking at, doing so doesn't really make the problem "smaller" in any way. Having this solution also isn't going to help us solve the original problem.
minDays - We're out of other things to try, so hopefully this is it. Can you see how having a table of solutions for (minDays - 1) could be used to solve the full problem?

I'm going to spoil this because it gives away the answer but I want to ask about it. Don't look, Batterypowered7 :mad:


I'm no high-falutin' degree haver, but isn't this just a really complicated way to say "breadth-first search"? This seems like a really simple problem with a well-established answer camouflaged by a bunch of 50 cent words.


Edit: As a high-falutin' frequent flyer status haver, that is not how frequent flyer status works either :colbert:

KillHour fucked around with this message at 07:34 on Jan 26, 2022

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

KillHour posted:

I'm going to spoil this because it gives away the answer but I want to ask about it. Don't look, Batterypowered7 :mad:


I'm no high-falutin' degree haver, but isn't this just a really complicated way to say "breadth-first search"? This seems like a really simple problem with a well-established answer camouflaged by a bunch of 50 cent words.


Not quite - the critical difference with dynamic programming is that the solutions to one subproblem are used to solve multiple subproblems in the next layer up. So once you've solved a subproblem once, you have to keep the answer around to avoid recomputing it the next time it's needed.

You can use recursion-with-memoization instead of explicitly building the table, but that memoization table is effectively the same table you'd have been building had you done it explicitly.

KillHour
Oct 28, 2007


Jabor posted:

Not quite - the critical difference with dynamic programming is that the solutions to one subproblem are used to solve multiple subproblems in the next layer up. So once you've solved a subproblem once, you have to keep the answer around to avoid recomputing it the next time it's needed.

You can use recursion-with-memoization instead of explicitly building the table, but that memoization table is effectively the same table you'd have been building had you done it explicitly.


I would get an F on that project because my brain would insist that this is obviously a graph theory problem so let me use graph theory to solve it, damnit! Yes, I realize the point is to teach the technique and not actually care about the specific answer. I don't do well in school. Thinking about it, though, the computational complexity should be the same - all you're doing with the table is flattening the graph every iteration, unless I'm missing some nuance there.

Edit: Wouldn't the table have to be n-dimensional with n being the number of steps from the start, making it fundamentally a graph anyways?

Maybe if I saw the table I'd understand the difference. Post your homework when it's done :v:

KillHour fucked around with this message at 07:52 on Jan 26, 2022

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

KillHour posted:

I would get an F on that project because my brain would insist that this is obviously a graph theory problem so let me use graph theory to solve it, damnit! Yes, I realize the point is to teach the technique and not actually care about the specific answer. I don't do well in school. Thinking about it, though, the computational complexity should be the same - all you're doing with the table is flattening the graph every iteration, unless I'm missing some nuance there.

There's a meet-in-the-middle trick you can do with the dynamic programming solution to replace a linear factor with a log one, which I don't see how you'd accomplish with BFS. That's only something to look at after you've got your head around the basic solution though.

KillHour
Oct 28, 2007


Jabor posted:

There's a meet-in-the-middle trick you can do with the dynamic programming solution to replace a linear factor with a log one, which I don't see how you'd accomplish with BFS. That's only something to look at after you've got your head around the basic solution though.

You saying that made me realize the difference - you're computing the cheapest option to get from everywhere to everywhere else in n days, not just starting from the place you are currently. So if you need to get from A to B in 4 days, by day 2, you can add up every combination of A => x and x => B to figure out the cheapest overall, and then that generalizes out to, as you said, log time. Here's the one thing I don't think works with that, though, but maybe you have the answer - what if the cheapest amount possible actually takes 5 days? The problem didn't say you couldn't go for more than the minimum, and it's possible a really cheap but long route could exist. You could do the same thing you do with a tree, which is keep going until no total amounts are less than the current best solution, but I don't think you can use the meet in the middle trick for that, at least not easily. Maybe if you compute all the tables for x <= log(n) days and then use a graph to search that smaller space?

There's a really interesting interplay here between number of cities and number of days that I think affects what solution has the best complexity.

Edit: I think instead of x <= log(n) you just need the subset where x is prime, up to the prime factors of n. Maybe I'm just overthinking it but this seems complicated to do optimally with tables

KillHour fucked around with this message at 08:31 on Jan 26, 2022

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Possibly you can start by computing the absolute cheapest way from each A to B regardless of days? Perhaps even using BFS for that, and logging each step into the same table that you'll use for the dynamic programming stage that takes into account the minimum days requirement so you don't need to repeat that work.

KillHour
Oct 28, 2007


Jabor posted:

Possibly you can start by computing the absolute cheapest way from each A to B regardless of days? Perhaps even using BFS for that, and logging each step into the same table that you'll use for the dynamic programming stage that takes into account the minimum days requirement so you don't need to repeat that work.

I literally thought of this while doing something else and came back to :doh: at myself


:shobon:


In my defense - if the number of days is small and the number of cities is large, which seems likely, a graph search would probably be faster.

KillHour fucked around with this message at 08:49 on Jan 26, 2022

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

KillHour posted:

You saying that made me realize the difference - you're computing the cheapest option to get from everywhere to everywhere else in n days, not just starting from the place you are currently. So if you need to get from A to B in 4 days, by day 2, you can add up every combination of A => x and x => B to figure out the cheapest overall, and then that generalizes out to, as you said, log time. Here's the one thing I don't think works with that, though, but maybe you have the answer - what if the cheapest amount possible actually takes 5 days?

What's the longest such a trip could take?

KillHour
Oct 28, 2007


rjmccall posted:

What's the longest such a trip could take?

Assuming the prices don't change and 0 or negative costs aren't allowed, it would have to be a travelling salesman path that visits every city exactly once

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Thinking about it more, I’m not sure that’s as directly useful as I was thinking it would be. Basically just something for the all-paths shortest path computation.

Batterypowered7
Aug 8, 2009

The mist that chills you keeps me warm.

I believe the answer is using the Floyd-Warshall algorithm (slightly modified).

N = number of vertices(cities), u = starting vertex, v = ending vertex, minDays, c = list of weighted edges (n x n matrix where cost[x][y] returns the weight of the edge)

code:
for s = 1 to N:

    for t = 1 to N:

        if (s, t) in E:
            //The base cost of traveling from s to t is equal to the weight of the edge
            T(0, s, t) = c[s][t]
        else:
            //If there is no edge from s to t, then the cost of traveling directly is infinite
            T(0, s, t) = infinite

for i = 1 to N:

	for s = 1 to N:

		for t = 1 to N:

			T(i, s, t) = min{????}

lowest = 0
weight = infinite

for i = minDays to n:

	if T(minDays, u, v) < weight:

		weight = T(minDays, u, v)
		lowest = minDays

return T(lowest, u, v)
The normal Floyd-Warshall algorithm calculates the following minimum:

code:
min{T(i-1, s, t), T(i-1, s, i) + T(i-1, i, t)}
But that doesn't generate a path of at least i edges.

code:
+--------+--------+--------+
|        | City 1 | City 2 |
+--------+--------+--------+
| City 1 |      1 |      3 |
| City 2 |      3 |      2 |
+--------+--------+--------+
In a graph like this, traversing from City 1 to City 2 where minDays = 1 should have a weight of 3, but if minDays = 2 then it should have a weight of 4 (City 1 -> City 1 -> City 2). Floyd-Warshall will just see that the shortest path has a weight of 3 and won't take into account that I want there to be minDays to N edges involved in the path.

Any suggestions where to take it from here?

E:

I'm aware the runtime for this algorithm is awful at O(N^3), but it's what is in the lecture notes, so I imagine it's what they're expecting us to use.

E2:

I've been spinning my wheels since Monday trying to figure this one out, but I haven't made any progress on the recurrences since posting. I think I'm just gonna have to take an L. Thank you for trying to help me, guys. I appreciate it!

Batterypowered7 fucked around with this message at 23:22 on Jan 27, 2022

Boba Pearl
Dec 27, 2019

by Athanatos

KillHour posted:

Holy poo poo you're getting ripped off. I'm not a web / front end developer, but this is for sure something you could either pay someone a modest amount of money to do or figure out yourself in a few days of futzing with it.

First, making a button: The way to make a link look like a button is to stick in an anchor tag with CSS styling made to look like a button. Here's a website with some examples of cool looking buttons that are links: https://fdossena.com/index.php?p=html5cool/buttons/i.frag

I spent 15 minutes futzing around with CSS in the browser to give an example of what you could do just with styling (and your style sheets could probably use a once-over by a developer because they're a bit of a mess, no offense).



Now for your expensive plugin problem. The "hard" part is writing a small piece of JS to figure out what the correct link is and replace the href field (the thing that tells the link where to go) with the correct destination. This isn't actually hard but I can't tell you how to do it without some digging because it depends on how your site is laid out.

I'm super embarassed, because I got some help from outside of this thread, and I found out what I'm trying to do is a default part of wordpress, and I was just too scatterbrained to figure it out, I found the coding document for wordpress after getting a bit of help, and then found the exact thing I need through stack exchange.

Boba Pearl posted:

So this does exactly what I want, but I don't know where to put the code from Stack Exchange, or how exactly it works, would I put it in the single post file in the theme?

https://wordpress.stackexchange.com/questions/149826/display-posts-from-the-same-category-using-next-previous-post-link

Wait actually I found something here:

https://developer.wordpress.org/reference/functions/next_post_link/

This would do it right? Where do I put that code? In the post template?

Then I can use this to get the first and last link, and use that to make the First and Last buttons, then I can just line them up across the page, and just rip out the plugin I was using for this.

https://wordpress.stackexchange.com/questions/363822/how-can-you-get-first-post-last-post-and-post-count-in-a-category

I'm planning to just copy paste this in my site, but I don't know where it goes. Normally I'd just google it for a while and figure it out by doing, but my brain is fried from school. Which is doubly embarassing because I'm a CNT major. How does the PHP in this work exactly?

Batterypowered7
Aug 8, 2009

The mist that chills you keeps me warm.

gently caress me, I think I finally got it. I'll post about it later for those curious.



Turns out I had the answer all along. Bellman-Ford guarantees i or fewer edges by doing a comparison between D(i,z) and D(i-1, y) + weight(y,z). The answer for this exercise is in the middle if the page. Instead of comparing to the existing value, we always just choose the minimum of all choices of D(i-1, y) + weight(y,z) for those particular values of i, y, and z. This guarantees adding an edge at every iteration.

E:

Runtime is O(NM) where M is the number of edges in the graph. There are N^2 edges, so runtime is O(N^3).

Batterypowered7 fucked around with this message at 18:40 on Jan 28, 2022

Batterypowered7
Aug 8, 2009

The mist that chills you keeps me warm.

I've got another problem I'm struggling with and I'm hoping for a little bit of direction.

Certain country in the Caribbean Sea recently held an election to choose its president. Every vote cast was electronic, but unfortunately, a recent power surge caused a malfunction in the system just before votes were counted. The only information saved consists of the following facts:

• All the N citizens casted their vote.
• Exactly one candidate received more than N/2 votes.
• We don’t know how many candidates there were.

You are hired to help using your expertise in algorithms. But you can only work with the local resources. As a result, you have access to a function Agree(X, Y ) which returns True if X and Y cast a vote for the same candidate, and returns False otherwise. You are not told the identity of the candidate! Design a Divide and Conquer algorithm that finds a single ballot that voted for the winning candidate. You may assume that every call of Agree(X, Y ) runs in constant time.

The naive approach is pretty easy to figure out:

code:
//Using 1-based indexing

compareTrue[] //have a list for numbers which have had a pair
votes[] //have a list for the number of votes

for i = 1 to N
	count = 0
	if i not in compareTrue
		add i to compareTrue //a voter is guaranteed to match with at least one person, themselves
		for j = 1 to N
			if agree(i,j)
				count++
				add j to compareTrue
		add {i, count} to votes

mostVotes = 0
index = 0

for i = 1 to len(votes)
	if votes[i][2] > mostVotes
		mostVotes = votes[i][2]
		index = i

return votes[index][1]
If citizen 1 voted for candidate 1, 2 for 2, 3 for 3, 4 for 4, and 5 through 10 all voted for candidate 5, then compareTrue and votes would look like this:

code:
compareTrue: {1}, votes: {{1,1}}
compareTrue: {1, 2}, votes: {{1,1}, {2,1}}
compareTrue: {1, 2, 3}, votes: {{1,1}, {2,1}, {3,1}}
compareTrue: {1, 2, 3, 4}, votes: {{1,1}, {2,1}, {3,1}, {4,1}}
compareTrue: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, votes: {{1,1}, {2,1}, {3,1}, {4,1}, {5,6}}
The runtime is O(N2) and it doesn't use a divide and conquer approach.

I thought about doing something along these lines:

code:

functionName(start,end)

//Start would be 1 and End would be N when we first call the function

voters = end- start+ 1

if voters <= 2
	if agree{start, end)
		do something???

else
	functionName(start, voters/2), functionName(voters/2 + 1, end)
If we take the same voting pattern I mentioned earlier, the subproblems will eventually do the following comparisons:

code:
1,2,3,4,5,6,7,8,9,10

1,2,3,4,5 | 6,7,8,9,10

1,2,3|4,5	6,7,8|9,10

1,1|2,3		6,7|8,8
This is where I'm stuck. I'm not sure what I'm looking to return at the base case (when we finally do a comparison). I thought maybe I'd be returning lists. If voters agreed, then I'd return a list with both voter numbers (or just the one number if I was comparing a voter to themselves). Eventually I'd have a list of lists and I could just return any one member of the longest list.

code:
finalVotes{{1}{2}{3}{4}{5,6,7,8,9,10}}
I'm just not sure how to get there, or if I should be doing something else entirely.

E:

The lectures this time cover Fast Integer Multiplication, Linear-Time Median, and Fast Fourier Transforms. I haven't been able to glean much insight from these on how to solve this problem.

Batterypowered7 fucked around with this message at 09:38 on Feb 3, 2022

nielsm
Jun 1, 2009



The second criteria, that the winner received half or more of the total votes cast should be your focus.

You can rephrase that, such that if you find a ballot that has half of all the ballots agreeing with it, you have found a ballot for the winner.
Conversely, any ballot where all of the agreeing ballots don't count up to half or more of the total votes are known to not be for the winner, so none of those matter.

Consider how it would look if each ballot consisted of a number, indicating the candidate voted for. What would it look like if you sorted the list of ballots by the candidate number?

Select a ballot at random, e.g. the first one. Test all remaining ballots whether they agree with this ballot, move those ballots to a separate list. If this list ends up with half or more of the total ballots, you found the winner. If not, discard all those ballots from further processing, and start over with a new randomly chosen ballot. That divides the problem into consecutively smaller problems until the solution is found. It's a linear-time median algorithm, essentially half of a QuickSort.

nielsm fucked around with this message at 10:27 on Feb 3, 2022

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Probabilistically linear is quite easy, since "winning" ballots make up more than half the list - just pick one at random, see if it agrees with the majority, repeat until you find one that does. There are probably some heuristics that do even better, like abandoning early for a new trial if the first three randomly-chosen comparisons don't match (would be very unlikely if this was the true winner), and keeping track if there's a big cluster that all agrees but doesn't quite win (so you can avoid it when picking your next starting point, and also avoid comparing against the elements of that cluster again).

Guaranteeing that you can do this in linear time seems a fair bit trickier.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Given that the hint is for a divide-and-conquer algorithm, perhaps the key insight they're looking for is that if you divide the input set in half, at least one of the halves will have a majority of winning voters.

Doom Mathematic
Sep 2, 2008
I think "Design a Divide and Conquer algorithm" is a massive mislead because you can do this in O(N) in a single pass over the ballots with no division or conquering (and constant storage).

The key point here is that you know the winning candidate received more than half of all the votes cast. Without this fact, this approach doesn't work.

Let's have a variable B, which contains a single ballot which voted for the front-runner so far as you've counted, and another variable, X, indicating that candidate's lead so far in the count. Before you begin counting, B is empty and the lead is 0. Now iterate over the ballots. For each ballot:

  • if B is empty, then set B to be this ballot and set the lead to 1.
  • if B is populated and the new ballot voted for the same candidate as B, keep B and increase its lead by 1.
  • if B is populated and the new ballot voted for a different candidate from B, decrease the lead by 1.
  • if decreasing the lead by 1 brings it to 0, discard B.

At the end of this process, B is your answer.


As for how you're supposed to deduce this algorithm from first principles, I have no idea. This is just one I happen to know the answer to because this algorithm is one of a few interesting ones covered in this talk which I watched one time:

https://www.youtube.com/watch?v=YA-nB2wjVcI

Xerophyte
Mar 17, 2008

This space intentionally left blank
Not sure I can give advice in a way that hasn't been covered, but for divide and conquer specifically it tends to help to think of how quicksort works, as it's sort of the quintessential divide and conquer algorithm.

To hint more specifically: In quicksort you first select a pivot element, then compare all other elements to the pivot to divide the large set into two smaller sets. Could those steps apply here?


Doom Mathematic posted:

I think "Design a Divide and Conquer algorithm" is a massive mislead because you can do this in O(N) in a single pass over the ballots with no division or conquering (and constant storage).

I assume the exercise specifies "design a Divide and Conquer algorithm" specifically to exclude that particular clever algorithm. The object of the exercise is to apply the principles of divide and conquer to the problem, not come up with the best possible algorithm.

Possibly I'm just saying that because I definitely did not arrive at that algorithm.

KillHour
Oct 28, 2007


Xerophyte posted:

Possibly I'm just saying that because I definitely did not arrive at that algorithm.

It is a really good algorithm though.

Batterypowered7
Aug 8, 2009

The mist that chills you keeps me warm.

The TAs specified that you'd receive no points if you didn't use a Divide and Conquer approach, so this is what I arrived at (using a little bit of the idea of the clever algorithm):

code:

function wrapper(N):

	//prepare our container of voters 1 through n
	container
	for i = 1 to N
		insert i into container

	return getMaxVote(container)[1]

//list, array, whatever
function getMaxVote(container):

	//if the container only has one element
	if len(container) == 1:
		//that voter's candidate gets one vote
		return [container[1], 1]

	k = floor(len(container)/2)

	left = getMaxVote(container[1:k]) //slice of 1 through k inclusive
	right = getMaxVote(container[k+1:len(container)]) //slice of k through n

	//if both left and right voted for the same person
	if Agree(left[1], right[1]):
		//return the voter on the left and sum their votes
		return [left[1], left[2] + right[2]]

	if !Agree(left[1], right[1]):
		//if left's candidate has more votes
		if left[2] > right[2]:
			return left
		
		//if right's candidate has more votes
		else if left[2] < right[2]:
			return right

		//if they have the same number of votes, just return left with one fewer votes
		else:
			return [left[1], left[2] - 1]
I tested the above in Python with a variety of inputs and it seems to work. Running time is O{n log n).

I also found a solution for a similar problem that might do it in O(n) time, but I wasn't confident when running it by hand, so I don't plan to submit it as my answer:

code:
GetMajorityElementLinear(a[1...n])
	//Input: Array a of objects
	//Output: Majority element of a

	if n = 2:
		if a[1] = a[2] return a[1]
	else return NO-MAJORITY-ELEMENT

	Create a temporary array temp
	for i = 1 to n:
		if a[i] = a[i+1]:
			Insert a[i] into temp
		i = i+1

	return GetMajorityElementLinear(temp)
The step that reads "if a = a[i + 1]" would be "if Agree(a,a[i+1]". What I was unsure about was that "i = i + 1" step. Is the person that wrote the algorithm just advancing i by one, or are they advancing it by an [i]additional one (since the for loop is guaranteed to advance it by one already), so that we're comparing 1 to 2, 3 to 4, etc? I [i]think it's the latter, but then it only really works when n is a power of 2, since as soon as n is odd we miss a comparison with the nth member. If we're not skipping any indices, then it just feels about as bad as doing two nested for loops (even though n decreases with each recursion).

KillHour
Oct 28, 2007


Batterypowered7 posted:

The TAs specified that you'd receive no points if you didn't use a Divide and Conquer approach, so this is what I arrived at (using a little bit of the idea of the clever algorithm):

code:

function wrapper(N):

	//prepare our container of voters 1 through n
	container
	for i = 1 to N
		insert i into container

	return getMaxVote(container)[1]

//list, array, whatever
function getMaxVote(container):

	//if the container only has one element
	if len(container) == 1:
		//that voter's candidate gets one vote
		return [container[1], 1]

	k = floor(len(container)/2)

	left = getMaxVote(container[1:k]) //slice of 1 through k inclusive
	right = getMaxVote(container[k+1:len(container)]) //slice of k through n

	//if both left and right voted for the same person
	if Agree(left[1], right[1]):
		//return the voter on the left and sum their votes
		return [left[1], left[2] + right[2]]

	if !Agree(left[1], right[1]):
		//if left's candidate has more votes
		if left[2] > right[2]:
			return left
		
		//if right's candidate has more votes
		else if left[2] < right[2]:
			return right

		//if they have the same number of votes, just return left with one fewer votes
		else:
			return [left[1], left[2] - 1]
I tested the above in Python with a variety of inputs and it seems to work. Running time is O{n log n).

I also found a solution for a similar problem that might do it in O(n) time, but I wasn't confident when running it by hand, so I don't plan to submit it as my answer:

code:
GetMajorityElementLinear(a[1...n])
	//Input: Array a of objects
	//Output: Majority element of a

	if n = 2:
		if a[1] = a[2] return a[1]
	else return NO-MAJORITY-ELEMENT

	Create a temporary array temp
	for i = 1 to n:
		if a[i] = a[i+1]:
			Insert a[i] into temp
		i = i+1

	return GetMajorityElementLinear(temp)
The step that reads "if a = a[i + 1]" would be "if Agree(a,a[i+1]". What I was unsure about was that "i = i + 1" step. Is the person that wrote the algorithm just advancing i by one, or are they advancing it by an [i]additional one (since the for loop is guaranteed to advance it by one already), so that we're comparing 1 to 2, 3 to 4, etc? I [i]think it's the latter, but then it only really works when n is a power of 2, since as soon as n is odd we miss a comparison with the nth member. If we're not skipping any indices, then it just feels about as bad as doing two nested for loops (even though n decreases with each recursion).

I think it depends on how looping works in your specific implementation / language. If you are using a loop that loops over an iterator, the iterator itself has the current state so anything you do to i inside the loop is thrown away. If the loop you're using just blindly increments i at the end of the loop, it's the latter. I assume the author intended the latter because the former doesn't do anything.

By way of example, Python can do either:

code:
for x in range(0, 3):
This loops over the iterator range and changing x inside the loop does nothing after the current iteration ends, as x is overwritten by the next element in the iterator.

code:
x = 0
while x < 3:
This checks x each time the loop ends, and modifying x affects the flow

Edit: Since it's pseudocode, you can't actually assume that the for loop itself is going to iterate x, so it might be just calling out that you increment x by 1 every iteration. C-like languages work like this - you have to specify what operation to apply to your iterator at the end of your for loop iteration. This is normally done explicitly at the beginning of the loop like

code:
for (int x = 0; x < 3; x++)
but there's no reason it has to other than convention.

TL;DR: Pseudocode can be really poo poo for algorithms because you might make assumptions about the theoretical language that your reader won't or vice versa.

KillHour fucked around with this message at 05:42 on Feb 4, 2022

Batterypowered7
Aug 8, 2009

The mist that chills you keeps me warm.

Also, the implementation I wasn't quite sure about had a "sanity check" function to make sure whoever you returned did indeed have n/2 + 1 votes or more, but the problem specifically states that one candidate got that many votes, so I omitted the step where we check. From what I've seen on the discussion boards, most people who have solved it have done so with n log n time complexity, so that's what I'm going to settle with. I might ask the TAs independently about this other solution after the assignment period is over.

KillHour
Oct 28, 2007


Batterypowered7 posted:

Also, the implementation I wasn't quite sure about had a "sanity check" function to make sure whoever you returned did indeed have n/2 + 1 votes or more, but the problem specifically states that one candidate got that many votes, so I omitted the step where we check. From what I've seen on the discussion boards, most people who have solved it have done so with n log n time complexity, so that's what I'm going to settle with. I might ask the TAs independently about this other solution after the assignment period is over.

The talk linked earlier specified that in the case of the fancy algorithm, you do actually have to do this and gave a hypothetical example where everyone votes for themselves and the last person Kramers in there and becomes pirate king by virtue of ticking the counter from 0 to 1. I feel like they have to want you to use something like that because otherwise why would they bother telling you that constraint?

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
While you’re right that your algorithm is O(n log n), it’s probably not for the reason you think.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Also, that GetMajorityElementLinear algorithm is totally busted; in addition to the boundary condition problems, it obviously fails on patterns like [1,2,1] or [1,2,2,1,1]. It also clearly is not linear, since the size of the list does not reliably decrease by more than 1 element. Maybe it’s been mistranslated, but I can’t even guess at what it’s trying to do.

Adbot
ADBOT LOVES YOU

KillHour
Oct 28, 2007


While we're on the subject of algorithms, maybe someone can help me out with something that is work related instead of school related.

My company's software has a matching process that is really neat but I think the actual algorithm for iterating over everything isn't very efficient and there's probably a really clever way to do this better. Obviously, the disclaimer here is that this isn't a neat problem in a vacuum - we actually make money off of this so don't feel obligated to make our product better for free. Also, I'm not worried about giving away any trade secrets because it's open source and you could just look it up if you cared enough.

That out of the way, here's what we do:

- The process is split into two steps - a matching step and a merging step. The matching step creates lists of documents to merge and the merging step actually performs the merges. This is to avoid issues with multiple threads trying to access the same document and having to wait for locks and all that fun stuff.

- Each step is split further into batches, and the batches are threaded across many servers so we have to take into account that batches can complete in any order and we can't really control where the batches are split easily, other than defining their size.

- The matching step loops over every input document in the batch and does the following:
- Check to see if the document was handled in another loop on the same batch. If so, skip
- Query the database to see if the document was already added to a list of matches from a previously completed batch. If so, skip
- Construct a query that will return all matching documents except for itself and execute it. For example, if your document had a name, an email address and a phone number, and you wanted to make sure at least two of those matched, it would create a query that was essentially (name AND email) OR (name AND phone) OR (phone AND email) AND NOT (input document).
- [Pedantic note - it actually assigns each property a score and queries for documents with a higher score than the minimum, but it's not relevant to the bigger algorithm]
- For the results, construct a new hypothetical document that contains all values for each property. For instance, let's say you had the following as your initial search document:

code:
{
  name: John Smith,
  phone: 555-555-5555,
  email: JSmith@company.com
}
and you received back the following results:

code:
[
  {
    name: John Smith,
    phone: 555-888-8888,
    email: JSmith@company.com
  },
  {
    name: John Smith,
    phone: 555-555-5555,
    email: john.smith@company.com
  }
]
it would create the following document in memory:

code:
{
  name: John Smith,
  phone: [555-555-5555, 555-888-8888],
  email: [JSmith@company.com, john.smith@company.com]
}
- Create a new query based on this new document that excludes the existing documents. In this case, it would basically be:

code:
  name: John Smith
  AND
  phone: 555-555-5555 OR 555-888-888
OR
  name: John Smith
  AND
  email: JSmith@company.com OR john.smith@company.com
OR
  phone: 555-555-5555 OR 555-888-888
  AND
  email: JSmith@company.com OR john.smith@company.com
AND NOT
  sourcedoc1 OR sourcedoc2 OR sourcedoc3
- Repeat until your query returns no results
- Create merge output document that lists results
- Note: It's possible for two batches to duplicate work if they both start on documents that end up in the same group after they have mutually queried for an existing merge document but before either process writes the document to the DB. Since both documents should have the same results, this is accepted as a relatively uncommon waste of work and the merging step has a way of detecting if it's already done the merge before and skipping it.

This works reasonably well if the size of your output groups / clusters is relatively small. But it becomes an issue when you have hundreds of results because of that final AND NOT query - you have to append a list of hundreds or thousands of results to exclude from the search results and the system starts to slow down. Because it's recursive, you end up with large clusters timing out, and since those large clusters don't write out to the DB as matches (since they timed out), you get batches retrying those clusters from every starting URI causing a huge slowdown for a relatively small percentage of the total number of documents.

My initial pass on a fix is to assume that when you have really large clusters like that, a lot of them are completely identical. So I've split it into a two pass process - find all the documents where all three fields match and merge those before starting the more complex match process. To do that, I'm concatenating the three fields together and generating a hash, which gets stored in a lexicon. Then I just iterate over the lexicon and merge all the documents with the same hash.

I think the two pass system will resolve a lot of the issues, but I'm wondering if there's a more clever algorithm for a distributed match system like this that doesn't have to keep track of all of the documents you've already found and pass list into the search function. My intuition is that there's a partitioning algorithm in graph theory that can help me but I'll be damned if I know what it is.

KillHour fucked around with this message at 06:27 on Feb 4, 2022

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply