It has been more than a year since the question was asked but I needed an answer myself and I had some time to come up with an algorithm that can produce the optimal result. I will explain it in case someone else needs it too. But you'll have to do some of the legwork yourself.
Edit: I used the Longest Increasing Subsequence algorithm from wikipedia instead of the Longest Common Subsequence. I didn't see that until later. I think my algorithm can be adapted to use the L.C.S. if you want but there may be both pros and cons.
To make it a little more clear why the longest increasing subsequence can result in the optimal solution, I would like to refer to this answer on another stack exchange question:
There is an invariant that each move can only increase the number in your longest increasing subsequence by at most 1.
If your initial array has k values in its longest increasing subsequence, you need n−k moves at least to get it sorted. This shows n−k moves is necessary.
The problem is, like you said, that while you move items around, a lot of other items move too and the location of those items become unknown.
Understanding this, let's step back for a moment. You gave the following arrays:
int[] original = { 201, 203, 208, 117, 89 };
int[] desired = { 208, 117, 89, 203, 201 };
To be able to take the longest increasing subsequence and actually end up with something useful, we must number the items in such a way so that we eventually end up with one long increasing sequence:
original2 = { 4, 3, 0, 1, 2 }; // Replace every number by the index of that number in the "desired" array.
desired2 = { 0, 1, 2, 3, 4 }; // Increasing sequence / indexes.
Now it's easy to see that the L.I.S. is [0, 1, 2] and the items that must be moved are [4, 3]. Axel's answer provides us with an algorithm to get original2
:
// find initial ordering
foreach(int io in original)
{
int pos = -1;
for (int i = 0; i < desired.Length; i++)
{
if (desired[i] == io)
{
pos = i;
break;
}
}
original2.Add(pos);
}
Let's present the array in a different way:

The ∅ represents a null item. The red (which have become purple-ish) numbers must be moved. In this case, 3 and 4 must be moved from somewhere between ∅ and 0 to somewhere between 2 and the end. Depending on the order in which items are moved, they may be inserted in a different location relative to the non-moving numbers. But we can know for certain between which non-moving numbers an item will end up at any time during the whole reordering process. Therefor, it is useful to use the non-moving numbers as anchors or beacons. These anchors can be used to determine the absolute position of an item at the time it will be removed and inserted.
To keep track of moving items relative to anchors, I will use the word "bucket". Which is just a name I gave it. Every bucket has an anchor, a list of items that have been inserted into the bucket and a list of items that will be removed from the bucket at some point.
class Bucket {
int anchor; // The non-moving item in front of the bucket
int[] inserted;
int[] toBeRemoved;
}
The layout of the bucket is synonymous to the plain array. Because all items that will be removed are gone at the end of the reordering, there is no point in trying to insert new items somewhere inbetween them. There won't be any inbetween left eventually. This is only difficult when calculating the indexes. Easier is to just insert all new items before the items that will be removed.
Below this is a graphical representation of a bucket. See how each item is still in the same place as in the original2
array.

Let's move an item. It doesn't really matter in which order you move them for this algorithm. For my own usecase I want them to be moved in the same order as that they end up in. It's possible to create a list of moves that need to be performed and to sort that list or, if you don't care about the order, you could just loop through the buckets and the toBeRemoved
items within them. I'm going to perform the latter one in the drawings.

To calculate the absolute index of the item we want to remove:
Calculate the size of every bucket before the bucket containing the item. Substract one to exclude the null-item in the first bucket.
numBeforeBucket = buckets.TakeWhile(b => b != sourceBucket)
.Sum(b => 1 + b.inserted.Length + b.toBeRemoved.Length) - 1
Calculate the number of items before the current item within the current bucket.
numBeforeInBucket = 1 + sourceBucket.inserted.Length + indexOfItemWithinTheToBeRemovedArray
Sum those values together.
sourceIndex = numBeforeBucket + numBeforeInBucket
Now remove the item from the bucket:
// You probably know the value already from one of the loop variables,
// but if you don't:
var item = sourceBucket.toBeRemoved[indexOfItemWithinTheToBeRemovedArray];
sourceBucket.toBeRemoved.Remove(item);
Note: if the slide.MoveTo(int toPos)
method in PowerPoint takes a target position as if the item hasn't been removed yet, you need to wait with removing the item from the bucket until you have calculated the target position as well.
To calculate the absolute index where to insert the item:
Calculate the size of every bucket before the bucket the item will be inserted into. Substract one to exclude the null-item in the first bucket.
numBeforeBucket = buckets.TakeWhile(b => b != targetBucket)
.Sum(b => 1 + b.inserted.Length + b.toBeRemoved.Length) - 1
Calculate the number of items before the new item within the destination bucket.
// Determine where to insert the item. Everything in "inserted" is
// already sorted so just get the index of the first item with a
// larger value. The way that .Insert(index, value) works is that
// the item will be inserted before the item currently occupying
// that index, pushing the occupying item to the right.
var i = 0;
for(; i < targetBucket.inserted.Length; i++) {
var current = targetBucket.inserted[i];
if(current > item) { // Item is the same variable from when we removed it.
break;
}
}
var indexOfItemWithinInsertedArray = i; // For clarity.
numBeforeInBucket = 1 + indexOfItemWithinInsertedArray
Sum the values together and substract one.
targetIndex = numBeforeBucket + numBeforeInBucket
Insert the item into the bucket:
targetBucket.inserted.Insert(indexOfItemWithinInsertedArray, item);

Now repeat for all items that must be moved.

I tried to use valid C#. I haven't done C# in a while though and my proof of concept was written in Go which does looping and array manipulation just a little different. You may need to change some .Length for some .Count(). If things don't work, I suggest looking for an off-by-one error.
If you need more explaining or exampling, just ask.