Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 除以一个数组';s元素乘以2乘以k,使数组';s和最小_C#_Algorithm_Linq_Data Structures - Fatal编程技术网

C# 除以一个数组';s元素乘以2乘以k,使数组';s和最小

C# 除以一个数组';s元素乘以2乘以k,使数组';s和最小,c#,algorithm,linq,data-structures,C#,Algorithm,Linq,Data Structures,我有一个由n个整数组成的数组,我需要将它的任意元素除以2(返回结果的上限)k次,这样的总和是最小的。与n相比,k的值可能非常大 我正在使用以下代码: private static int GetMaxSum(int[] array, int k) { int n = array.Length; for (int i = 0; i < k; i++) { var indexAtMax = GetMaxI

我有一个由n个整数组成的数组,我需要将它的任意元素除以2(返回结果的上限)k次,这样的总和是最小的。与n相比,k的值可能非常大

我正在使用以下代码:

    private static int GetMaxSum(int[] array, int k)
    {
        int n = array.Length;

        for (int i = 0; i < k; i++)
        {
            var indexAtMax = GetMaxIndex(array);
            if (array[indexAtMax] == 1) break;
            array[indexAtMax] = array[indexAtMax] / 2 + array[indexAtMax] % 2;
        }
        return array.Sum();
    }

    private static int GetMaxIndex(int[] array)
    {
        int maxIndex = 0;
        int max = array[0];
        for  (int i=1; i<array.Length;i++)
        {
            if (array[i] > max)
            {
                max = array[i];
                maxIndex = i;
            }
        }
        return maxIndex;
    }
私有静态int GetMaxSum(int[]数组,int k)
{
int n=数组长度;
for(int i=0;i

我们如何通过使用max heap或其他数据结构进一步提高性能?

除非我误解了您的要求,否则您的解决方案看起来太复杂了(根据评论,显然是错误的)

我现在真的想不透,但全局解决方案不是由最优的中间步骤组成吗?你划分的顺序是不相关的,问题是线性的

如果是这种情况,您只需在每个步骤中评估最佳分割,这并不难做到:

static void Minimize(int[] arr, int k)
{
    for (var j = 0; j < k; j++)
    {
        var maxGainIndex = -1;
        var maxGain = int.MinValue;

        for (var i = 0; i < arr.Length; i++)
        {
            var gain = arr[i] - (arr[i]/2 + arr[i] % 2);

            if (gain > maxGain)
            {
                maxGain = gain;
                maxGainIndex = i;
            }

        }

        arr[maxGainIndex] -= maxGain;
    }
}
可在此处找到基准测试代码:
我提出的算法的性能增益相当惊人(x15),这是意料之中的,因为对于这样一个简单的问题,您的解决方案在初始评估时最多过于复杂。

由于假设是k>>n,较简单的算法的阶数为O(kn),这可能会导致太多的迭代。 我写这段代码时考虑了这个问题,以及如何限制排序或计算最小/最大值。我将数组划分为子数组,这样就可以在不考虑操作顺序的情况下对子数组执行操作

    private static int GetMinSum(int[] array, int k)
    {
        int n = array.Length;
        var sum = 0;
        k = GetOptimizedListAndK(array, n, k, out var lists);

        //If more sublists are needed  
        if (k > 0)
        {
            var count = lists.CountSum;
            var key = lists.Key;
            if (key > 0)
            {
                var poweroftwo = 1 << key;
                sum += count * poweroftwo - k * poweroftwo / 2;
                var dictionary2 = GetDictionary(array, lists, poweroftwo);
                key = dictionary2.Keys.Last();

                while (k > 0 && key > 0)
                {

                    var list2 = dictionary2[key];
                    count = list2.Count;
                    if (k >= count)
                    {
                        list2.ForEach(
                             index => array[index] = array[index] / 2 + array[index] % 2);


                        dictionary2.Remove(key);

                        key = dictionary2.Keys.LastOrDefault();

                        k -= count;
                    }
                    else
                    {
                        if (k <= Log2(count))
                        {

                            for (int i = 0; i < k; i++)
                            {

                                var indexAtMax = GetMaxIndex(list2, array);
                                array[indexAtMax] = array[indexAtMax] / 2 + array[indexAtMax] % 2;
                            }
                            k = 0;
                        }
                        if (count - k <= Log2(count))
                        {
                            var minIndexes = GetMinIndexes(list2, array, count - k);

                            foreach (var i in list2)
                            {
                                if (!minIndexes.Contains(i))
                                {
                                    array[i] = array[i] / 2 + array[i] % 2;
                                }
                            }

                            k = 0;
                        }
                        if (k > 0)
                        {
                            poweroftwo = 1 << key;
                            sum += list2.Count * poweroftwo - k * poweroftwo / 2;
                            dictionary2 = GetDictionary(array, list2, poweroftwo);
                            key = dictionary2.Keys.Last();
                        }
                    }
                }
            }
        }
        return array.Sum() + sum;
    }
    private static int GetOptimizedListAndK(int[] array, int n, int k, out Lists lists)
    {
        lists = null;
        Dictionary<int, Lists> dictionary = new Dictionary<int, Lists>();
        PopulatePowerBasedDictionary(array, n, dictionary);
        var key = dictionary.Keys.Max();
        while (key > 0 && k > 0)
        {
           lists = dictionary[key];
           var count = lists.CountSum;

            if (k >= count)
            {
                lists.ForEach(list => list.ForEach(index => array[index] = array[index] / 2 + array[index] % 2));
                if (key > 1)
                {
                    if (dictionary.TryGetValue(key - 1, out var lowerlists))
                    {
                        lowerlists.AddRange(lists);
                        lowerlists.CountSum += count;
                    }
                    else dictionary.Add((key - 1), lists);
                }

                dictionary.Remove(key);

                key--;

                k -= count;
            }
            else
            {
                if (k < Log2(count))
                {
                    for (int i = 0; i < k; i++)
                    {
                        var indexAtMax = GetMaxIndex(lists, array);
                        array[indexAtMax] = array[indexAtMax] / 2 + array[indexAtMax] % 2;
                    }
                    k = 0;
                }
                if (count - k < Log2(count))
                {
                    var minIndexes = GetMinIndexes(lists, array, count - k);
                    foreach (var list in lists)
                    {
                        foreach (var i in list)
                        {
                            if (!minIndexes.Contains(i))
                            {
                                array[i] = array[i] / 2 + array[i] % 2;
                            }
                        }
                    }
                    k = 0;
                }
                break;
            }
        }
        return k;
    }

    private static void PopulatePowerBasedDictionary(int[] array, int n, Dictionary<int, Lists> dictionary)
    {
        for (int i = 0; i < n; i++)
        {
            if (array[i] < 2) continue;
            var log2 = Log2(array[i]);
            if (dictionary.TryGetValue(log2, out var lists))
            {
                lists[0].Add(i);
                lists.CountSum++;
            }
            else
            {
                lists = new Lists(1,log2) { new List<int> { i } };
                dictionary.Add(log2, lists);
            }
        }
    }

    private static int GetMaxIndex(List<int> list, int[] array)
    {
        var maxIndex = 0;
        var max = 0;

        foreach (var i in list)
        {
            if (array[i] > max)
            {
                maxIndex = i;
                max = array[i];
            }
        }

        return maxIndex;
    }

    private static SortedDictionary<int, List<int>> GetDictionary(int[] array, Lists lists, int poweroftwo)
    {
        SortedDictionary<int, List<int>> dictionary = new SortedDictionary<int, List<int>>();


        foreach (var list in lists)
        {
            foreach (var i in list)
            {
                array[i] = array[i] - poweroftwo;
                if (array[i] < 2)
                {
                    continue;
                }
                var log2 = Log2(array[i]);
                if (dictionary.TryGetValue(log2, out var list2))
                {
                    list2.Add(i);
                }
                else
                {
                    list2 = new List<int> { i };
                    dictionary.Add(log2, list2);
                }

            }
        }

        return dictionary;
    }
    private static SortedDictionary<int, List<int>> GetDictionary(int[] array, List<int> list, int poweroftwo)
    {
        SortedDictionary<int, List<int>> dictionary = new SortedDictionary<int, List<int>>();

        foreach (var i in list)
        {
            array[i] = array[i] - poweroftwo;
            if (array[i] < 2)
            {
                continue;
            }
            var log2 = Log2(array[i]);
            if (dictionary.TryGetValue(log2, out var list2))
            {
                list2.Add(i);
            }
            else
            {
                list2 = new List<int> { i };
                dictionary.Add(log2, list2);
            }


        }

        return dictionary;
    }
    private static int GetMaxIndex(Lists lists, int[] array)
    {
        var maxIndex = 0;
        var max = 0;
        foreach (var list in lists)
        {
            foreach (var i in list)
            {
                if (array[i]>max)
                {
                    maxIndex = i;
                    max = array[i];
                }
            }
        }
        return maxIndex;
    }
    private static HashSet<int> GetMinIndexes(Lists lists, int[] array, int k)
    {
        var mins = new HashSet<int>();
        var minIndex = 0;
        var min = int.MaxValue;
        for (int j = 0; j < k; j++)
        {
            foreach (var list in lists)
            {
                foreach (var i in list)
                {
                    if (array[i] < min && !mins.Contains(i))
                    {
                        minIndex = i;
                        min = array[i];
                    }
                }
            }
            mins.Add(minIndex);
            min = int.MaxValue;
        }

        return mins;
    }
    private static HashSet<int> GetMinIndexes(List<int> list, int[] array, int k)
    {
        var mins = new HashSet<int>();
        var minIndex = 0;
        var min = int.MaxValue;
        for (int j = 0; j < k; j++)
        {

                foreach (var i in list)
                {
                    if (array[i] < min && !mins.Contains(i))
                    {
                        minIndex = i;
                        min = array[i];
                    }
                }
            mins.Add(minIndex);
            min = int.MaxValue;
        }

        return mins;
    }
    private static int Log2(int n)
    {
        return BitOperations.Log2((uint)n);
    }
私有静态int GetMinSum(int[]数组,int k)
{
int n=数组长度;
var总和=0;
k=GetOptimizedListAndK(数组、n、k、out变量列表);
//如果需要更多的子列表
如果(k>0)
{
var count=lists.CountSum;
var key=lists.key;
如果(键>0)
{
var poweroftwo=1 0&&key>0)
{
var list2=字典2[key];
count=list2.count;
如果(k>=计数)
{
列表2.ForEach(
index=>array[index]=array[index]/2+array[index]%2);
字典2.移除(键);
key=dictionary2.Keys.LastOrDefault();
k-=计数;
}
其他的
{
if(k0)
{
列表=字典[键];
var count=lists.CountSum;
如果(k>=计数)
{
lists.ForEach(list=>list.ForEach(index=>array[index]=array[index]/2+array[index]%2));
如果(键>1)
{
if(dictionary.TryGetValue(键-1,out var lowerlists))
{
lowerlists.AddRange(列表);
lowerlists.CountSum+=计数;
}
添加((键-1),列表);
}
删除(键);
键--;
k-=计数;
}
其他的
{
如果(kmax)
{
maxIndex=i;
max=数组[i];
}
}
返回最大索引;
}
私有静态SortedDictionary GetDictionary(int[]数组,列表,int-poweroftwo)
{
SortedDictionary=新的SortedDictionary();
foreach(列表中的变量列表)
{
foreach(列表中的变量i)
{
数组[i]=数组[i]-幂函数
    private static int GetMinSum(int[] array, int k)
    {
        int n = array.Length;
        var sum = 0;
        k = GetOptimizedListAndK(array, n, k, out var lists);

        //If more sublists are needed  
        if (k > 0)
        {
            var count = lists.CountSum;
            var key = lists.Key;
            if (key > 0)
            {
                var poweroftwo = 1 << key;
                sum += count * poweroftwo - k * poweroftwo / 2;
                var dictionary2 = GetDictionary(array, lists, poweroftwo);
                key = dictionary2.Keys.Last();

                while (k > 0 && key > 0)
                {

                    var list2 = dictionary2[key];
                    count = list2.Count;
                    if (k >= count)
                    {
                        list2.ForEach(
                             index => array[index] = array[index] / 2 + array[index] % 2);


                        dictionary2.Remove(key);

                        key = dictionary2.Keys.LastOrDefault();

                        k -= count;
                    }
                    else
                    {
                        if (k <= Log2(count))
                        {

                            for (int i = 0; i < k; i++)
                            {

                                var indexAtMax = GetMaxIndex(list2, array);
                                array[indexAtMax] = array[indexAtMax] / 2 + array[indexAtMax] % 2;
                            }
                            k = 0;
                        }
                        if (count - k <= Log2(count))
                        {
                            var minIndexes = GetMinIndexes(list2, array, count - k);

                            foreach (var i in list2)
                            {
                                if (!minIndexes.Contains(i))
                                {
                                    array[i] = array[i] / 2 + array[i] % 2;
                                }
                            }

                            k = 0;
                        }
                        if (k > 0)
                        {
                            poweroftwo = 1 << key;
                            sum += list2.Count * poweroftwo - k * poweroftwo / 2;
                            dictionary2 = GetDictionary(array, list2, poweroftwo);
                            key = dictionary2.Keys.Last();
                        }
                    }
                }
            }
        }
        return array.Sum() + sum;
    }
    private static int GetOptimizedListAndK(int[] array, int n, int k, out Lists lists)
    {
        lists = null;
        Dictionary<int, Lists> dictionary = new Dictionary<int, Lists>();
        PopulatePowerBasedDictionary(array, n, dictionary);
        var key = dictionary.Keys.Max();
        while (key > 0 && k > 0)
        {
           lists = dictionary[key];
           var count = lists.CountSum;

            if (k >= count)
            {
                lists.ForEach(list => list.ForEach(index => array[index] = array[index] / 2 + array[index] % 2));
                if (key > 1)
                {
                    if (dictionary.TryGetValue(key - 1, out var lowerlists))
                    {
                        lowerlists.AddRange(lists);
                        lowerlists.CountSum += count;
                    }
                    else dictionary.Add((key - 1), lists);
                }

                dictionary.Remove(key);

                key--;

                k -= count;
            }
            else
            {
                if (k < Log2(count))
                {
                    for (int i = 0; i < k; i++)
                    {
                        var indexAtMax = GetMaxIndex(lists, array);
                        array[indexAtMax] = array[indexAtMax] / 2 + array[indexAtMax] % 2;
                    }
                    k = 0;
                }
                if (count - k < Log2(count))
                {
                    var minIndexes = GetMinIndexes(lists, array, count - k);
                    foreach (var list in lists)
                    {
                        foreach (var i in list)
                        {
                            if (!minIndexes.Contains(i))
                            {
                                array[i] = array[i] / 2 + array[i] % 2;
                            }
                        }
                    }
                    k = 0;
                }
                break;
            }
        }
        return k;
    }

    private static void PopulatePowerBasedDictionary(int[] array, int n, Dictionary<int, Lists> dictionary)
    {
        for (int i = 0; i < n; i++)
        {
            if (array[i] < 2) continue;
            var log2 = Log2(array[i]);
            if (dictionary.TryGetValue(log2, out var lists))
            {
                lists[0].Add(i);
                lists.CountSum++;
            }
            else
            {
                lists = new Lists(1,log2) { new List<int> { i } };
                dictionary.Add(log2, lists);
            }
        }
    }

    private static int GetMaxIndex(List<int> list, int[] array)
    {
        var maxIndex = 0;
        var max = 0;

        foreach (var i in list)
        {
            if (array[i] > max)
            {
                maxIndex = i;
                max = array[i];
            }
        }

        return maxIndex;
    }

    private static SortedDictionary<int, List<int>> GetDictionary(int[] array, Lists lists, int poweroftwo)
    {
        SortedDictionary<int, List<int>> dictionary = new SortedDictionary<int, List<int>>();


        foreach (var list in lists)
        {
            foreach (var i in list)
            {
                array[i] = array[i] - poweroftwo;
                if (array[i] < 2)
                {
                    continue;
                }
                var log2 = Log2(array[i]);
                if (dictionary.TryGetValue(log2, out var list2))
                {
                    list2.Add(i);
                }
                else
                {
                    list2 = new List<int> { i };
                    dictionary.Add(log2, list2);
                }

            }
        }

        return dictionary;
    }
    private static SortedDictionary<int, List<int>> GetDictionary(int[] array, List<int> list, int poweroftwo)
    {
        SortedDictionary<int, List<int>> dictionary = new SortedDictionary<int, List<int>>();

        foreach (var i in list)
        {
            array[i] = array[i] - poweroftwo;
            if (array[i] < 2)
            {
                continue;
            }
            var log2 = Log2(array[i]);
            if (dictionary.TryGetValue(log2, out var list2))
            {
                list2.Add(i);
            }
            else
            {
                list2 = new List<int> { i };
                dictionary.Add(log2, list2);
            }


        }

        return dictionary;
    }
    private static int GetMaxIndex(Lists lists, int[] array)
    {
        var maxIndex = 0;
        var max = 0;
        foreach (var list in lists)
        {
            foreach (var i in list)
            {
                if (array[i]>max)
                {
                    maxIndex = i;
                    max = array[i];
                }
            }
        }
        return maxIndex;
    }
    private static HashSet<int> GetMinIndexes(Lists lists, int[] array, int k)
    {
        var mins = new HashSet<int>();
        var minIndex = 0;
        var min = int.MaxValue;
        for (int j = 0; j < k; j++)
        {
            foreach (var list in lists)
            {
                foreach (var i in list)
                {
                    if (array[i] < min && !mins.Contains(i))
                    {
                        minIndex = i;
                        min = array[i];
                    }
                }
            }
            mins.Add(minIndex);
            min = int.MaxValue;
        }

        return mins;
    }
    private static HashSet<int> GetMinIndexes(List<int> list, int[] array, int k)
    {
        var mins = new HashSet<int>();
        var minIndex = 0;
        var min = int.MaxValue;
        for (int j = 0; j < k; j++)
        {

                foreach (var i in list)
                {
                    if (array[i] < min && !mins.Contains(i))
                    {
                        minIndex = i;
                        min = array[i];
                    }
                }
            mins.Add(minIndex);
            min = int.MaxValue;
        }

        return mins;
    }
    private static int Log2(int n)
    {
        return BitOperations.Log2((uint)n);
    }
public class Lists:List<List<int>>
{
    public int Key { get; set; }
    public int CountSum { get; set; }

    public Lists(int countSum, int key):base()
    {
        CountSum = countSum;
        Key = key;
    }
}