我试图解决的问题给了我一个像
这样的矩阵10101
11100
11010
00101
这些行应该代表一个人知道的主题;例如由10101
代表的人1知道主题1,3和5,但不知道2或4.我需要找到2人团队可以知道的最大主题数;例如第1人和第3人的团队知道所有主题,因为在10101
和11010
之间,每个索引都有1
个。
我有一个O(n ^ 2)解决方案
string[] topic = new string[n];
for(int topic_i = 0; topic_i < n; topic_i++)
{
topic[topic_i] = Console.ReadLine();
}
IEnumerable<int> teamTopics =
from t1 in topic
from t2 in topic
where !Object.ReferenceEquals(t1, t2)
select t1.Zip(t2, (c1, c2) => c1 == '1' || c2 == '1').Sum(b => b ? 1 : 0);
int max = teamTopics.Max();
Console.WriteLine(max);
通过所有测试用例,它不会超时。我怀疑它不够快的原因与时间复杂性有关,而不是LINQ机器的开销。但我无法想出更好的方法。
我想也许我可以将主题索引映射到知道它们的人,比如
1 -> {1,2,3}
2 -> {2,3}
3 -> {1,2,4}
4 -> {3}
5 -> {1,4}
但我无法想到从哪里开始。
你能给我一个&#34;提示&#34;?
答案 0 :(得分:3)
我们说我们有n个人和m个主题。
我认为你的算法是O(n ^ 2 * m),其中n是人数,因为:
from t1 in topic
让你O(n)from t2 in topic
将您带到O(n ^ 2)t1.Zip(t2 ...
让你到O(n ^ 2 * m)我看到的优化是首先修改字符串:
等...
然后你分析字符串s1。您选择所有可能的1对(O(n^2)
元素),这些元素显示了一起知道第一个主题的人对。然后从该列表中选择一对并检查他们是否也知道第二个主题,依此类推。当他们不在时,将其从列表中删除并转到另一对。
不幸的是,这看起来也是O(n^2 * m)
,但实际上这应该更快。对于非常稀疏的矩阵,它应该接近O(n 2 ),对于密集矩阵,它应该很快找到一对。
答案 1 :(得分:2)
思想:
(newSkills & ~bestSkills) != 0
- 意思是:被测试的人有“最好的”工人没有的东西;这使得具有互补技能的工人加上“最佳”工人(你必须明确包括他们,因为上面的~
/ !=0
测试将失败)0
与行1
- (m-1)
进行比较,但行1
行2
- (m-1)
,行5
到6
- (m-1)
等~((~0)<<k)
比较,其中k
是要测试的位数)这仍然是O(n) + O(m^2)
,其中m <= n是技能与技能最高的人
病理但技术上正确的答案:
插入Thread.Sleep(FourYears)
- 所有解决方案现在基本上都是O(1)
答案 2 :(得分:2)
您的解决方案渐近有效,因为您需要检查所有对以达到最大值。您可以通过使用BitArray
对象替换字符串来提高代码效率,如下所示:
var topic = new List<BitArray>();
string line;
while ((line = Console.ReadLine()) != null) {
topic.Add(new BitArray(line.Select(c => c=='1').ToArray()));
}
var res =
(from t1 in topic
from t2 in topic
select t1.Or(t2).Count).Max();
Console.WriteLine(res);