Click here to Skip to main content
15,891,431 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello. I am learning C#.In the below code I want to implement an algorithm for the fractional knapsack problem.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace codeproject
{


    class Program
    {

        static double KnapsackLINQ(double capacity, double[] weights, double[] values)
        {
            double value = 0.0;

            var dictionary = weights.Zip(values, (w, v) => new { w, v 
                      }).ToDictionary(item => item.w, item => item.v);

            foreach (KeyValuePair<double, double> kvp in dictionary)
            {
                dictionary[kvp.Key] = kvp.Value / kvp.Key;
            }

            var mylist = dictionary.ToList();


            mylist.Sort((pair1,pair2) => pair1.Value.CompareTo(pair2.Value));


            double Max = mylist.LastOrDefault().Value;
            double a = 0;

            var myordereddic = mylist.ToDictionary(x => x.Key , x => 
                                x.Value).OrderByDescending(x => x.Value);

            var mydic = myordereddic.ToDictionary(x => x.Key , x => x.Value);

            double wi = 0.0;
            foreach (KeyValuePair<double, double> kvp in mydic)
            {
                if (capacity == 0)
                {
                    return value;
                }

                wi = kvp.Key;
                a = Math.Min(wi, capacity);
                value += a * kvp.Value;
                wi -= a;
                
                capacity -= a;
            }
            return value;
        }



        static void Main(string[] args)
        {
             int[] firstline;
             firstline = Array.ConvertAll(Console.ReadLine().Trim().Split(' '), 
                               Convert.ToInt32);
             List<double> values = new List<double>();
             List<double> weights = new List<double>();

             double[] myarray;
            for (int i = 0; i < firstline[0]; i++)
            {
                myarray = Array.ConvertAll(Console.ReadLine().Trim().Split(' '), 
                                  Convert.ToDouble);
                 values.Add(myarray[0]);
                 weights.Add(myarray[1]);
            }
            double[] v = values.ToArray();
            double[] w = weights.ToArray();

            double ans = KnapsackLINQ(firstline[1], w, v);
            System.Console.WriteLine(String.Format("{0:0.0000}" , ans));

        }
    }
}


Problem description
Input Format. The first line of the input contains the number 𝑛 of items and the capacity 𝑊 of a knapsack.
The next 𝑛 lines define the values and weights of the items. The 𝑖-th line contains integers 𝑣𝑖 and 𝑤𝑖—the value and the weight of the 𝑖-th items, respectively.

Constraints. 1 ≤ 𝑛 ≤ 103, 0 ≤ 𝑊 ≤ 2 · 106; 0 ≤ 𝑣𝑖 ≤ 2 · 106, 0 < 𝑤𝑖 ≤ 2 · 106 for all 1 ≤ 𝑖 ≤ 𝑛. All the numbers are integers.

Output Format. Output the maximal value of fractions of items that fit into the knapsack. The absolute value of the difference between the answer of your program and the optimal value should be at most 10−3. To ensure this, output your answer with at least four digits after the decimal point (otherwise your answer, while being computed correctly, can turn out to be wrong because of rounding issues).

For example:
Input:
C#
3 50
60 20
100 50
120 30

output:
C#
180.0000


The problem is when I run and debug this code on my own system it works correctly but, when I submit it on Coursera it shows an error that:
List index is out of range

Failed case #1/13: (Wrong answer)
wrong output format: list index out of range
Input:
3 50
60 20
100 50
120 30

Your output:

Your stderr:

Unhandled Exception:
System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
  at System.ThrowHelper.ThrowInvalidOperationException (System.ExceptionResource resource) [0x0000b] in <8f2c484307284b51944a1a13a14c0266>:0 
  at System.Collections.Generic.Dictionary`2+Enumerator[TKey,TValue].MoveNext () [0x00016] in <8f2c484307284b51944a1a13a14c0266>:0 
  at coursera.Program.KnapsackLINQ (System.Double capacity, System.Double[] weights, System.Double[] values) [0x000a5] in <bf680f74f7a64f95ac43cd249ff6d2dc>:0 
  at coursera.Program.Main (System.String[] args) [0x000c0] in <bf680f74f7a64f95ac43cd249ff6d2dc>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
  at System.ThrowHelper.ThrowInvalidOperationException (System.ExceptionResource resource) [0x0000b] in <8f2c484307284b51944a1a13a14c0266>:0 
  at System.Collections.Generic.Dictionary`2+Enumerator[TKey,TValue].MoveNext () [0x00016] in <8f2c484307284b51944a1a13a14c0266>:0 
  at coursera.Program.KnapsackLINQ (System.Double capacity, System.Double[] weights, System.Double[] values) [0x000a5] in <bf680f74f7a64f95ac43cd249ff6d2dc>:0 
  at coursera.Program.Main (System.String[] args) [0x000c0] in <bf680f74f7a64f95ac43cd249ff6d2dc>:0 

Correct output:
180.000
 (Time used: 0.01/1.50, memory used: 16347136/2684354560.)


What I have tried:

I think the problem is because of my first foreach loop. I have tried to use LINQ functions because there exists a time-limit test for this practice.
Actually, I don't want to change my code a lot. But I will be really grateful for any help and advice. Thanks.
Posted
Updated 30-Sep-21 4:36am
v2

1 solution

Quote:
Collection was modified; enumeration operation may not execute.
C#
foreach (KeyValuePair<double, double> kvp in dictionary)
{
    dictionary[kvp.Key] = kvp.Value / kvp.Key;
}
You are modifying a collection inside a foreach loop that's iterating over the same collection. That never ends well - it's the cause of your error message.

It's not clear to me why you need this loop at all. You could simply modify the value when you create the dictionary:
C#
var dictionary = weights
    .Zip(values, (w, v) => new { w, v })
    .ToDictionary(item => item.w, item => item.v / item.w);

// No need for the "foreach" loop now...

It's also not clear to me why you keep converting between Dictionary<TKey, TValue> and List<KeyValuePair<TKey, TValue>>. It looks like you're trying to sort the values, but a Dictionary<TKey, TValue> is inherently not sorted.

Instead, you should use OrderByDescending to get an IEnumerable<KeyValuePair<double, double>>, and work directly with that.
C#
IEnumerable<KeyValuePair<double, double>> sortedValues = dictionary.OrderByDescending(p => p.Value);
double max = sortedValues.FirstOrDefault().Value;
foreach (KeyValuePair<double, double> kvp in sortedValues)
{
    ...
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900