using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication2
{
public class Pair<IClass, JClass>
{
public IClass I { get; set; }
public JClass J { get; set; }
}
public class Pair<IClass, JClass, KClass>
{
public IClass I { get; set; }
public JClass J { get; set; }
public KClass K { get; set; }
public Pair(IClass i, JClass j, KClass k)
{
I = i;
J = j;
K = k;
}
public Pair(IClass i, JClass j)
{
I = i;
J = j;
}
}
public class Split
{
private const double Expected = 0.7;
public static List<Pair<double, double, decimal>> Resolve(List<double> m, List<double> n)
{
Console.WriteLine(".................................start to get resolution.................................");
// m: sum array
// n: item array
n = n.OrderByDescending(x => x).ToList();
var mapping = new Dictionary<Pair<int, double>, List<List<int>>>();
List<List<int>> temp;
int i = 0;
foreach (var mth in m)
{
temp = GetComb(mth, n);
if (temp.Count > 0) mapping[new Pair<int, double> { I = i, J = mth }] = temp;
else
{
Console.WriteLine("data error");
return null;
}
i++;
}
var result = GetOpt(mapping.Values.ToList());
if (IsTrueSolution(result)) Console.WriteLine("this is a real solution");
foreach (var item in result)
{
item.I = n[(int)item.I];
item.J = n[(int)item.J];
item.K = (decimal)item.I + (decimal)item.J;
Console.WriteLine(item.K);
}
return result;
}
static bool IsTrueSolution(List<Pair<double, double, decimal>> result)
{
var list = result.SelectMany(m => new int[] { (int)m.I, (int)m.J }).ToList();
return list.Distinct().Count() == list.Count;
}
/// <summary>
///
/// </summary>
/// <param name="set"></param>
/// <returns>index in the 2nd-layered list</returns>
static List<Pair<double, double, decimal>> GetOpt(List<List<List<int>>> set)
{
set = set.OrderBy(m => m.Count).ToList();
var set1 = new List<int>();
int i = 0, len = set.Count;
int j = 0;
Stack<Pair<int, int>> stack = new Stack<Pair<int, int>>();
Pair<int, int> pair;
int max = 0;
List<Pair<int, int>> result = null;
ulong iter = 0;
double realTimeElapsed = 0;
var watcher = new System.Diagnostics.Stopwatch();
watcher.Start();
do
{
if (watcher.Elapsed.TotalSeconds > 540) break;
while (i < len)
{
iter++;
while (j < set[i].Count)
{
iter++;
if (!IsCollided(set1, set[i][j]))
{
MergeToFirst(set1, set[i][j]);
stack.Push(new Pair<int, int> { I = i, J = j });
if (stack.Count > max)
{
max = stack.Count;
if (max >= (int)len * Expected) result = stack.Select(m => new Pair<int, int> { I = m.I, J = m.J }).ToList();
realTimeElapsed = watcher.Elapsed.TotalSeconds;
}
break;
}
j++;
}
i++;
j = 0;
}
if (stack.Count != len)
{
do
{
iter++;
pair = stack.Pop();
RemoveFromFirst(set1, set[pair.I][pair.J]);
i = pair.I;
j = pair.J + 1;
while (j < set[i].Count)
{
iter++;
if (!IsCollided(set1, set[i][j]))
{
MergeToFirst(set1, set[i][j]);
stack.Push(new Pair<int, int> { I = i, J = j });
if (stack.Count > max)
{
max = stack.Count;
if (max >= (int)len * Expected) result = stack.Select(m => new Pair<int, int> { I = m.I, J = m.J }).ToList();
realTimeElapsed = watcher.Elapsed.TotalSeconds;
}
break;
}
j++;
}
} while (j >= set[i].Count && (stack.Count > 0));
i++;
j = 0;
if ((stack.Count + len - i) < max)
{
i = len;
}
if (stack.Count == 0)
{
set1.Clear();
}
}
else
{
break;
}
} while (stack.Count > 0 || i < len);
Console.WriteLine("total iteration:{0} with real time elapsed: {1}", iter, realTimeElapsed);
var solution = new List<Pair<double, double, decimal>>();
if (result == null) result = stack.Select(m => new Pair<int, int> { I = m.I, J = m.J }).ToList();
foreach (var p in result)
{
solution.Add(new Pair<double, double, decimal>(set[p.I][p.J][0], set[p.I][p.J][1]));
}
return solution;
}
/// <summary>
///
/// </summary>
/// <param name="set1"></param>
/// <param name="set2">has only 2 items</param>
/// <returns></returns>
static bool IsCollided(List<int> set1, List<int> set2)
{
if (set1.Count == 0 || set2.Count == 0) return false;
var result = false;
foreach (var v in set2)
{
if (result) break;
result = result || (BSearch(set1, v) != -1);
}
return result;
}
static int BSearch(List<int> set1, int v)
{
var pos = -1;
int i = 0, j = set1.Count - 1, mid;
while (i <= j)
{
mid = (i + j) / 2;
if (set1[mid] > v)
{
if (i == mid) i = mid + 1;
else i = mid;
}
else if (set1[mid] < v)
{
if (j == mid) j = mid - 1;
else j = mid;
}
else
{
pos = mid;
break;
}
}
return pos;
}
static void MergeToFirst(List<int> set1, List<int> set2)
{
foreach(var v in set2)
{
set1.Insert(GetInsertPos(set1, v), v);
}
}
static int GetInsertPos(List<int> set1, int v)
{
if (set1.Count == 0) return 0;
int i = 0, j = set1.Count - 1, mid;
while (i <= j)
{
mid = (i + j) / 2;
if (set1[mid] > v)
{
if (mid + 1 >= set1.Count) return mid + 1;
if (set1[mid + 1] < v) return mid + 1;
if (i == mid) i = mid + 1;
else i = mid;
}
else if (set1[mid] < v)
{
if ((mid - 1 < 0) || set1[mid - 1] > v) return mid;
if (j == mid) j = mid - 1;
else j = mid;
}
else
{
return mid;
}
}
return -1;
}
static void RemoveFromFirst(List<int> set1, List<int> set2)
{
foreach (var v in set2)
{
set1.RemoveAt(BSearch(set1, v));
}
}
static List<List<int>> GetComb(double value, List<double> items, double deviation = 0)
{
var result = new List<List<int>>();
int i = 0, j = items.Count - 1;
decimal sum;
while (i < j)
{
sum = (decimal)items[i] + (decimal)items[j] - (decimal)value;
if (sum > 0) i++;
else if (sum < 0) j--;
else
{
result.Add(new List<int> { i, j });
i++; j--;
}
}
return result;
}
}
}