Does exponential precalculation contradict polynomial-time reduction? - complexity-theory

Suppose I have a problem A that has at least one yes and one no instance which may take exponentially long to find.
In Problem B we get 2 instances of A and are supposed to decide whether or not 1 of them is a yes instance and one of them is a no instance
Assuming we know one "No" instance of A we can create an instance of B by giving (I,"No-Instance") where I is an arbitrary input for A which we want to decide. (Effectively transforming every instance of A into a B instance in O(1))
In this case, if I is a "Yes" instance , the instance of B will also be a "Yes" instance (same for "no")
Now, to find this No instance that we're going to use for every transformation we may need exponential time once.
Does this factor into the transformation's runtime? Aka. is it still a polynomial-time transformation then?

Related

C++: Time complexity for vector push_back() - trying to understand the C++ Primer 5th Ed - Stanley Lipmann

I am reading C++ Primer on vector push_back() and trying to understand the below statement.
Every implementation is required to follow a strategy that ensures that it is efficient
to use push_back to add elements to a vector. Technically speaking, the execution
time of creating an n-element vector by calling push_back n times on an initially
empty vector must never be more than a constant multiple of n
I have read quite a bit of data structure on this but just do not understand the one in BOLD ITALIC. Not sure what the author is trying to say especially the word "MULTIPLE".
Wondering as an example if n=5 does the author meant multiple of 5 (e.g. 5 or 10 or 15 etc)?
Appreciate any help.
The author is saying that there must exist a constant value c, such that inserting n elements into the vector does never take longer than c*n.
For example that c could be for a given element type one microsecond per item. In that case inserting 100 items into the vector will not take longer than 100 microseconds.
Technically that isn't exactly the guarantee you have. There is usually no obvious way to precisely define such a time bounds on real systems. And if the time required in the constructors of the element type is not constant, it may also impact this kind of time guarantee.
Instead the standard makes such a guarantee only about the number of times that an operation will be performed on the elements. So here for example if the vector's element type is a class type, c could be 3 per element, which would mean that inserting 100 elements will at most call constructors of the element type 300 times.
This is meant as an asymptotic bound and not to determine actual time execution takes for small values of n.
This requirement is also known as amortized constant time complexity for individual push_back.

Is a while loop with a nested for loop O(n) or O(n^2)?

I have 2 blocks of code. One with a single while loop, and the second with a for loop inside the while loop. My professor is telling me that Option 1 has an algorithm complexity of O(n) and Option 2 has an algorithm complexity of O(n^2), however can't explain why that is, other than pointing to the nested for loops. I am confused because both perform the exact same number of calculations for any given size N, which doesn't seem to be indicative that they have different algorithm complexities.
I'd like to know:
a) if my professor is correct, and how they can boast the same calculations but have different big Os.
b) if my professor is incorrect and they are the same complexity, is it O(n) or O(n^2)? Why?
I've used inline comments denoted by '#' to note the computations. Packages to deliver should be N. Self.trucks is a list. self.isWorkDayComplete is a boolean determined by whether all packages have been delivered.
Option 1:
# initializes index for fake for loop
truck_index = 0
while(not self.workDayCompleted):
# checks if truck index has reached end of self.trucks list
if(truck_index != len(self.trucks)):
# does X amount of calculations required for delivery of truck's packages
while(not self.trucks[truck_index].isEmpty()):
trucks[truck_index].travel()
trucks[truck_index].deliverPackage()
if(hub.packagesExist()):
truck[truck_index].travelToHub()
truck[truck_index].loadPackages()
# increments index
truck_index += 1
else:
# resets index to 0 for next iteration set through truck list
truck_index = 0
# does X amount of calculations required for while loop condition
self.workDayCompleted = isWorkDayCompleted()
Option 2:
while(not self.workDayCompleted):
# initializes index (i)
# each iteration checks if truck index has reached end of self.trucks list
# increments index
for i in range(len(trucks)):
# does X amount of calculations required for Delivery of truck's packages
while(not self.trucks[i].isEmpty()):
trucks[i].travel()
trucks[i].deliverPackage()
if(hub.packagesExist()):
truck[i].travelToHub()
truck[i].loadPackages()
# does X amount of calculations required for while loop condition
self.workDayCompleted = isWorkDayCompleted()
Any help is greatly appreciated, thank you!
It certainly seems like these two pieces of code are effectively implementing the same algorithm (i.e. deliver a package with each truck, then check to see if the work day is completed, repeat until the work day is completed). From this perspective you're right to be skeptical.
The question becomes: are they O(n) or O(n2)? As you've described it, this is impossible to determine because we don't know what the conditions are for the work day being completed. Is it related to the amount of work that has been done by the trucks? Without that information we have no ability to reason about when the outer loop exits. For all we know the condition is that each truck must deliver 2n packages and the complexity is actually O(n 2n).
So if your professor is right, my only guess is that there's a difference between the implementations of isWorkDayCompleted() between the two options. Barring something like that, though, the two options should have the same complexity.
Regardless, when it comes to problems like this it is always important to make sure that you're both talking about the same things:
What n means (presumably the number of trucks)
What you're counting (presumably the number of deliveries and maybe also the checks for the work day being done)
What the end state is (this is the red flag for me -- the work day being completed needs better defined)
Subsequent edits lead me to believe both of these options are O(n), since they ultimately perform one or two "travel" operations per package, depending on the number of trucks and their capacity. Given this, I think the answer to your core question (do those different control structures result in different complexity analysis) is no, they don't.
It also seems unlikely that the internals are affecting the code complexity in some important way, so my advice would be to get back together with your professor and see if they can expand on their thoughts. It very well might be that this was an oversight on their part or that they were trying to make a more subtle point about how some of the component you're using were implemented.
If you get their explanation and there is something more complex going on that you still have trouble understanding, that should probably be a separate question (perhaps linked to this one).
a) if my professor is correct, and how they can boast the same calculations but have different big Os.
Two algorithms that do the same number of "basic operations" have the same time complexity, regardless how the code is structured.
b) if my professor is incorrect and they are the same complexity, is it O(n) or O(n^2)? Why?
First you have to define: what is "n"? Is n the number of trucks? Next, does the number of "basic operations" per truck the same or does it vary in some way?
For example: If the number of operations per truck is constant C, the total number of operations is C*n. That's in the complexity class O(n).

Is there an established algorithm for reaching a goal through the sequential application of known cause and effect tuples?

Let's say that I want to create a fictional product called g.
I know that:
a+b=c
x+y=z
and finally that
c+z=g
So clearly if I start off with products
a,b,x,y
I can create g in three steps:
a+b=c
x+y=z
c+z=g
So a naive algorithm for reaching a goal could be:
For each component required to make the goal (here c and z), recursively find a cause and effect tuple that can create that component.
But there are snags with that algorithm.
For example, let's say that my cause and effect tuples are:
a+b=c
x+y+c=z (NOTE THE EXTRA 'c' REQUIRED!!)
c+z=g
Now when I run my naive algorithm I will do
a+b=c
x+y+c=z (Using up the 'c' I created in the previous step)
c+z=g (Uh oh! I can't do this because I don't have the 'c' any more)
It seems like quite a basic area of research - how we can combine known causes and effects to reach a goal - so I suspect that work must have been done on it, but I've looked around and couldn't find anything and I don't really know where to look now.
Many thanks for any assistance!
Assuming that using a product consumes one item of it, which can then be replaced by producing a second item of that product, I would model this by giving each product a cost and working out how to minimize the cost of the final product. In this case I think this is the same as minimizing the costs of every product, because minimizing the cost of an input never increases the cost of any output. You end up with loads of equations like
a=min(b+c, d+e, f+g)
where a is the cost of a product that can be produced in alternative ways, one way consuming units with cost of b and c, another way consuming units with costs of d and e, another way consuming units with costs of f and g, and so on. There may be cycles in the associated graph.
One way to solve such a problem would be to start by assigning the cost infinity to all products not originally provided as inputs (with costs) and then repeatedly reducing costs where equations show a way of calculating a cost less than the current cost, keeping track of re-calculations caused by inputs not yet considered or reductions in costs. At each stage I would consider the consequences of the smallest input or recalculated value available, with ties broken by a second component which amounts to a tax on production. The outputs produced from a calculation are always at least as large as any input, so newly produced values are always larger than the recalculated value considered, and the recalculated value considered at each stage never decreases, which should reduce repeated recalculation.
Another way would be to turn this into a linear program and throw it at a highly optimized guaranteed polynomial time (at least in practice) linear programming solver.
a = min(b+c, d+e, f+g)
becomes
a = b+c-x
a = d+e-y
a = f+g-z
x >= 0
y >= 0
z >= 0
minimize sum(x+y+z+....)

Two sets of items. Each element of set A a unique match in set B. Match each item of set A to item in set B in O(nlogn) time

So, to clarify the question:
Set A and Set B
every element in set A has a partner in set B
you can not sort either set based upon comparing it to members of the same set, ie, each b element of B is indistinguishable from any other b of set B (likewise for A).
when Ai is matched with Bi you can tell if Bi > Ai, Bi < Ai or Bi = Ai.
design an algorithm with O(nlogn) running time.
The obvious answer with quadratic time is trivial and not helpful -- although it's the best I've come up with yet. The log(n) makes me think that I should be using recursion or a binary tree of some sort, but I'm not sure how could create a binary tree without being able to compare elements from the same set. Also, I'm not sure how to use a recursive call to any greater effect than just running nested for loops. Any tips would be greatly appreciated.
You haven't stated it very clearly, but your question looks suspiciously like the Matching Nuts and Bolts problem.
The idea there is to pick a random nut a, find the matching bolt b. Partition the bolts using nut a, and partition the nuts using Bolt b, and then recurse, like quicksort does.
(Of course, we are talking about the average case being nlogn, rather than the worst case).

Clever algorithm for checking on equality

We need to implement next feature:
Suppose we have a list of some objects.
We need to say what objects are the same and what are not.
Suppose 1 is equal to 2 and 2 is equal to 5.
So 1 is equal to 5 and we don't need to check them.
Does this algorithm exist?
Any ideas would be very great.
I think this can be thought of as having sets of elements which are equal. And IMO Disjoint Set Data Structure will be very efficient in maintaing such set of records. The basic idea is to first put every element as a seperate set, whenever you encounter a equality relation you take the set to which those elements belong and merge them. The run time for merge and lookup are sub-logarithmic if you use path compression. http://en.wikipedia.org/wiki/Disjoint-set_data_structure
You want a Disjoint Set strucutre with path compression. It's very simple to implement, and the performance is close to O(1).
If you have a graph where the vertices are the objects and there's an edge between known equal objects, then every object connected to another object is also equal. So, to test if object A equals object B, you are testing if a path exists between A and B in that graph.
You can use any graph searching algorithm to do this. Depth-first search would be a good start.
If you want to find all connected pairs then you could use Tarjan's algorithm to find all strongly connected components. Within each component, all objects are equal.

Resources