【400分】求一个分组的算法,想了很久也没解决

叫我三三 2018-01-10 11:26:22
现在有几千条只有NA,NB两个列数据需要分组。
每组的NA列都是相同的,NB有交叉。
分组规则是:
1、合并后NB不同的数量最多20条;
2、每组数量尽可能的等于或接近20条;
3、同NA不能拆分;
4、NB数量多的优先合并;
5、同NB相同的优先合并;
6、如果有多种组合满足以上条件,选NA最少的;
7、分成的组需要尽可能的接近理论分组的个数情况,理论分组的个数=去重后的NB个数/20+(NB%20>0?1:0);
请大家帮忙想一下,C# 、 SQL都行,谢谢。


下面的例子只是列举第一组应该怎么取,实际数组有几千个NA.
...全文
501 9 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
xuzuning 2018-01-11
  • 打赏
  • 举报
回复
4、NB数量多的优先合并; 此条由数据组织保证,可以先排序 5、同NB相同的优先合并; 此条由代码 51 行保证 6、如果有多种组合满足以上条件,选NA最少的;算法本身保证(从最小的组合开始试探)
xuzuning 2018-01-11
  • 打赏
  • 举报
回复
比较暴力,但逻辑清晰。应该能看懂吧
        static void Main(string[] args)
{
var a = new List<Item>()
{

new Item() { NA = "NA01", NB = new List<string>() {"NB01", "NB02","NB03","NB04","NB05","NB06","NB07","N08","NB09","NB10","NB11", "NB12","NB13","NB14","NB15","NB16"}},
new Item() { NA = "NA02", NB = new List<string>() {"NB13", "NB14","NB15","NB16","NB17","NB18","NB19","N20","NB21","NB22","NB23", "NB24"}},
new Item() { NA = "NA03", NB = new List<string>() {"NB07","N08","NB09","NB10","NB24","NB25","NB26"}},
new Item() { NA = "NA04", NB = new List<string>() {"NB11", "NB12","NB13","NB27","NB28"}},
new Item() { NA = "NA05", NB = new List<string>() {"NB29"}},
new Item() { NA = "NA06", NB = new List<string>() {"NB10"}},
new Item() { NA = "NA07", NB = new List<string>() {"NB23"}},
};
var res = new List<List<Item>>();
var v = 20;

while (a.Count > 0)
{
var dis = a.Aggregate(new List<string>(), (a1, b) => a1.Union(b.NB).ToList()).Count();
var all = a.Aggregate(new List<string>(), (a1, b) => a1.Concat(b.NB).ToList()).Count();
if (dis > v)
{
foreach (var r in Find(a, v))
{
//这里可以有多个返回结果,为简化只取了第一个
dis = a.Where(s => r.Contains(s.NA)).Aggregate(new List<string>(), (a1, b) => a1.Union(b.NB).ToList()).Count();
all = a.Where(s => r.Contains(s.NA)).Aggregate(new List<string>(), (a1, b) => a1.Concat(b.NB).ToList()).Count();
Console.WriteLine("全部:{0} 去重:{1} 成员:{2}", all, dis, string.Join(", ", r));
var ks = a.Where(x => r.Contains(x.NA)).ToArray();
foreach (var k in ks) a.Remove(k);

break;
}
}
else
{
Console.WriteLine("全部:{0} 去重:{1} 成员:{2}", all, dis, string.Join(", ", a.Select(x=>x.NA)));
break;
}
}
}
static IEnumerable<List<string>> Find(List<Item> o, int v, int deep=0)
{
var r = new List<List<string>>();
var st = new List<List<string>>();
var na = o.Select(x => x.NA).ToList();
foreach (var t in o) r.Add(new List<string>() { t.NA });
for(var i=0;i<r.Count;i++)
{
var p = o.Where(s => r[i].Contains(s.NA)).Aggregate(new List<string>(), (a, b) => a.Concat(b.NB).ToList());
na = o.Where(x => !r[i].Contains(x.NA)).OrderByDescending(x => x.NB.Count + x.NB.Intersect(p).Count() / x.NB.Count).Select(x => x.NA).ToList();

foreach(var t in na)
{
var tmp = new List<string>(r[i]).Concat(new List<string>() { t }).ToList();
var cnt = o.Where(s => r[i].Contains(s.NA)).Aggregate(new List<string>(), (x, y) => x.Concat(y.NB).ToList()).Count();
var uncnt = o.Where(s => tmp.Contains(s.NA)).Aggregate(new List<string>(), (x, y) => x.Union(y.NB).ToList()).Count();
if (uncnt == v)
{
if (st.Count > 0 && st.Where(x => x.Except(tmp).Count() == 0).Count() > 0)
{
continue;
}
st.Add(tmp);
yield return tmp;
}
if(uncnt < v) r.Add(tmp);
}
}
}
kampoo 2018-01-11
  • 打赏
  • 举报
回复
关注一下,感觉像一个ACM 题目,估算一下算法复杂度试试暴力。
叫我三三 2018-01-10
  • 打赏
  • 举报
回复
引用 1 楼 starfd 的回复:
你这样不就是要遍历生成所有的可能,然后从中取最优的么?那你时间要求怎么样,全部遍历一遍这时间可不会少
数据正确就行,对时间要求不高。
  • 打赏
  • 举报
回复
你这样不就是要遍历生成所有的可能,然后从中取最优的么?那你时间要求怎么样,全部遍历一遍这时间可不会少
叫我三三 2018-01-10
  • 打赏
  • 举报
回复
来个人,帮帮忙啊
叫我三三 2018-01-10
  • 打赏
  • 举报
回复
引用 3 楼 xuzuning 的回复:
这是 01背包问题的扩展
由于 同NA不能拆分,可视同 NA 的 NB 个数为权重,这是典型的 01背包问题
条件 4,、5、6 只是在分配时附加了约束

背包的算法好解。
我用的贪婪算法。
但是加上后面的约束,我就卡住了。

private void RightEntity()
{
GroupDN = new List<Entity[]>();
List<Entity> tempList = new List<Entity>();tempList.AddRange(dnList);
while (tempList.Count > 0)
{
List<Entity> GroupEntity = new List<Entity>();
var NowTemp = tempList.OrderByDescending(t => t.Num).First();
GroupEntity.Add(NowTemp);
tempList.Remove(NowTemp);
Entity Next;
int Sum = NowTemp.Num;
do
{
Next = tempList.Where(t=>t.Num<=20-Sum).OrderByDescending(t => t.Num).FirstOrDefault();
if (Next != null) {
GroupEntity.Add(Next);
Sum = Sum + Next.Num;
tempList.Remove(Next);
}
}
while (Next != null);
GroupDN.Add(GroupEntity.ToArray());
}
}

public class Entity
{
public Entity(string dn, int num)
{
DN = dn; Num = num;
}
public string DN { get; private set; }
public int Num { get; private set; }
}



xuzuning 2018-01-10
  • 打赏
  • 举报
回复
这是 01背包问题的扩展 由于 同NA不能拆分,可视同 NA 的 NB 个数为权重,这是典型的 01背包问题 条件 4,、5、6 只是在分配时附加了约束

111,098

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧