【问题标题】:Finding order between many events在许多事件之间寻找顺序
【发布时间】:2016-07-28 13:28:17
【问题描述】:

目前正在解决一个谜题并寻找一些关于按事件排序的提示。我想知道我应该遵循的程序到底是什么。考虑一下这个

我输入一个数字,然后n 输入 每个输入有两个事件,其中event1 event2event1 发生在event2 之前。

考虑输入

6
Eatfood Cuthair
Eatfood BrushTeeth
School  EatFood
School  DoHair
DoHair   Meeting
Meeting Brushteeth

输出将是

school -> dohair-> eatfood -> meeting -> cuthair -> brushteeth

按这个顺序。因为如果我们把所有的东西都写下来,学校确实是第一件事,然后是dohair。如果存在多个可能的排序,则只需输出一个。您可以假设所有事件都以某种方式连接,并且不存在循环依赖关系。

我正在考虑做的是制作两个数组,一个包含所有eventOne's 和所有eventTwo's。我不确定从这里去哪里。我想在javascript中做到这一点。谢谢!建议任何提示或算法

另一个输入

6
vote_140_prof announce_140_prof
vote_140_prof first_day_of_classes
dev_shed_algo vote_140_prof
dev_shed_algo do_hair
do_hair big_meeting
big_meeting first_day_of_classes

输出

dev_shed_algo do_hair vote_140_prof big_meeting announce_140_prof first_day_of_classes

我在我的电脑上找到了解决方案文件,它是我不知道的python,但希望这能帮助其他人理解这个问题

from collections import defaultdict

def toposort(graph, roots):
    res = [i for i in roots]
    queue = [i for i in roots]
    while queue:
        for i in graph[queue.pop(0)]:
            if i not in res:
                res.append(i)
                queue.append(i)
    return res

graph = defaultdict(set)
a_set = set()
b_set = set()

for i in range(int(input())):
    a, b = input().split()
    a_set.add(a)
    b_set.add(b)
    graph[a].add(b)

print(" ".join(i for i in toposort(graph, a_set - b_set)))

我的尝试

var words =
    'vote_140_prof announce_140_prof vote_140_prof first_day_of_classes devshed_algo vote_140_prof dev_shed_algo do_hair do_hair big_meeting big_meeting first_day_of_classes';

var events = words;

events = events.split(/\s+/);
console.log(events);

var obj = {};
for (var i = 0 ; i < events.length ; i++)
    {
        var name = events[i];
        if(obj[name] === undefined )
            {
                obj[name] = [];
            }

        obj[name].push(events[i%2 === 1 ? i-1 : i+1]);
    }
console.log(obj);

格式化

function sequenceEvents(pairs){
        var edges = pairs.reduce(function(edges,pair){
            edges.set(pair[0],[]).set(pair[1],[]);
            new Map();
        });

        pairs.forEach(function(edges,pair){

            edges.set(pair[0],[]).set(pair[1],[]);

        });

        var result = [];

        while(edges.size){
            var children = new Set([].concat.apply([],[...edges.value()]));
            var roots = [...edges.keys()].filter(function(event){
                !children.has(event);
            });

            if(!roots.length) throw "Cycle detected";
        roots.forEach(function(root){
           result.push(root);
           edges.delete(root);

        });

        }

        return result;

    }

【问题讨论】:

  • 所以您输入了一个引用第一个列表中的一个事件的数字,它需要从第一个列表中输出该事件,然后从第二个列表中输出该事件?
  • 我忘了添加如果存在多个可能的排序,只需输出一个。我想这个问题有点奇怪,我不太清楚你的意思。基本上这个想法是找到发生的第一个事件。即使某事是一个输入的事件一,它也可以是另一个输入的事件 2,在这种情况下,输入 2 的输入 1 是第一个发生的事情,依此类推
  • 可能是相当复杂的代码,因为您需要检查循环引用、孤儿等。What have you tried so far?
  • 哦,是的“你可能假设所有事件都以某种方式连接,并且不存在循环依赖关系。”,我会在里面添加。道歉
  • 添加了一个我在电脑上的问题文件夹中找到的python解决方案,目前正在尝试解决这个问题并更新你们

标签: javascript


【解决方案1】:

Python 算法不正确。此输入将失败:

3
A B
A C
C B

它会输出:

A, B, C

...与最后一条规则相冲突。这是因为它错误地假设任何根事件的子事件都可以安全地添加到结果中,并且不依赖于其他事件。在上述情况下,它会将 A 标识为根,并将 B 和 C 标识为其子项。然后它将从该列表中弹出 C,并将其添加到结果中,而不会看到 C 依赖于 B,而 B 尚未出现在结果中。

正如其他人所指出的,您需要确保大小写一致。 BrushteethBrushTeeth 被认为是不同的事件。 EatFoodEatfood 也是如此。

我在这里提供一个解决方案。我希望内联 cmets 能很好地解释正在发生的事情:

function sequenceEvents(pairs) {
    // Create a Map with a key for each(!) event, 
    // and add an empty array as value for each of them.
    var edges = pairs.reduce(
        // Set both the left and right event in the Map 
        //   (duplicates get overwritten)
        (edges, pair) => edges.set(pair[0], []).set(pair[1], []),
        new Map() // Start with an empty Map
    );
    // Then add the children (dependent events) to those arrays:
    pairs.forEach( pair => edges.get(pair[0]).push(pair[1]) );

    var result = [];
    // While there are still edges...
    while (edges.size) {
        // Get the end points of the edges into a Set
        var children = new Set( [].concat.apply([], [...edges.values()]) );
        // Identify the parents, which are not children, as roots
        var roots = [...edges.keys()].filter( event => !children.has(event) );
        // As we still have edges, we must find at least one root among them.
        if (!roots.length) throw "Cycle detected";
        roots.forEach(root => {
            // Add the new roots to the result, all events they depend on
            // are already in the result:
            result.push(root);
            // Delete the edges that start with these events, since the
            // dependency they express has been fulfilled:
            edges.delete(root);
        });
    }
    return result;
}


// I/O
var input = document.querySelector('#input');
var go = document.querySelector('#go');
var output = document.querySelector('#output');

go.onclick = function() {
    // Get lines from input, ignoring the initial number
    // ... then split those lines in pairs, resulting in
    // an array of pairs of events
    var pairs = input.value.trim().split(/\n/).slice(1)
                     .map(line => line.split(/\s+/));
    var sequence = sequenceEvents(pairs);
    output.textContent = sequence.join(', ');
}
Input:<br>
<textarea id="input" rows=7>6
EatFood CutHair
EatFood BrushTeeth
School  EatFood
School  DoHair
DoHair   Meeting
Meeting BrushTeeth
</textarea>
<button id="go">Sequence Events</button>
<div id="output"></div>

没有箭头功能也没有apply

在 cmets 中,您表示您希望首先使用不带箭头功能的代码:

function sequenceEvents(pairs) {
    // Create a Map with a key for each(!) event, 
    // and add an empty array as value for each of them.
    var edges = pairs.reduce(function (edges, pair) {
        // Set both the left and right event in the Map 
        //   (duplicates get overwritten)
        return edges.set(pair[0], []).set(pair[1], []);
    }, new Map() ); // Start with an empty Map
    // Then add the children (dependent events) to those arrays:
    pairs.forEach(function (pair) {
        edges.get(pair[0]).push(pair[1]);
    });

    var result = [];
    // While there are still edges...
    while (edges.size) {
        // Get the end points of the edges into a Set
        var children = new Set(
            [...edges.values()].reduce(function (children, value) {
                return children.concat(value);
            }, [] )
        );
        // Identify the parents, which are not children, as roots
        var roots = [...edges.keys()].filter(function (event) {
            return !children.has(event);
        });
        if (!roots.length) throw "Cycle detected";
        roots.forEach(function (root) {
            // Add the new roots to the result, all events they depend on
            // are already in the result:
            result.push(root);
            // Delete the edges that start with these events, since the
            // dependency they express has been fulfilled:
            edges.delete(root);
        });
    }
    return result;
}

【讨论】:

  • 顺便问一下,您是否尝试过我在问题中提出的其他测试用例,或者该测试用例是错误的(我刚刚将其粘贴到网站上),或者我没有正确输入?我说的是dev_shed_algo的测试用例......来自我的问题
  • 另外,我尝试将其格式化为我更熟悉的语法,我在顶部添加了我的尝试,但看起来该死的 => 再次让我感到困惑,即使我在你解释了一百万次之后我以为我明白了哈哈。我在上面编辑过,我写的很清楚是错误的,但我真的不知道如何翻译它。我通常喜欢做的是采用更简单的语法版本,然后用更“复杂”的语法重写它
  • 另一个测试用例实际上是完全相同的问题——它只是使用了不同的词。将每个vote_140_prof 替换为EatFood,将每个announce_140_prof 替换为CutHair... 等等,你就遇到了第一个问题!现在,这种谜题通常有不止一个正确答案,所以你不能说如果两个程序产生不同的解决方案,那么其中一个就一定是错误的。他们都可能是对的。
  • 关于您为=&gt; 语法所做的翻译:filterreduce 回调函数需要return 语句。如果不使用大括号,则在 =&gt; 语法中隐含。在开头的reduce 中,您还犯了另一个小错误:new Map() 部分不应出现在功能块中;它是reduce 的第二个参数(在函数之后)。
  • 使用无箭头代码在我的答案中添加了一个部分。
【解决方案2】:

好的。这是我对这个问题的看法。

var makePair = function(i0, i1) {
    return {start: i0, end: i1};
};

var mp = makePair;

var makeBefores = function(pairs) {
    var befores = {};
  pairs.forEach(function(pair) {
    if (befores[pair.end] == null) {
        befores[pair.end] = [pair.start];
    } else {
        befores[pair.end].push(pair.start);
    }
    if (befores[pair.start] == null) {
        befores[pair.start] = [];
    }
  });
  for (var key in befores) {
    console.log("after " + key + "there is:");
    for (var i = 0; i < befores[key].length; i++) {
        console.log(befores[key][i]);
    }
  }

  return befores;
};

var shouldGoBefore = function(item, before) {
    for (var i = 0; i < before.length; i++) {
    if (item == before[i]) {
        return true;
    }
  }
  return false;
};

var sortEvents = function(pairs) {
    if (pairs.length === 0) {
    return [];
  }
  if (pairs.length === 1) {
    return [pairs[0].start, pairs[0].end];
  }
  console.log(pairs);
  var befores = makeBefores(pairs);
  var sorted = [];
  for (var key in befores) {
    var added = false;
    for (var i = 0; i < sorted.length; i++) {
    console.log('checking if ' + sorted[i] + ' should go before ' + befores[key]);
        if (shouldGoBefore(sorted[i], befores[key])) {
            //console.log("splicing");
        sorted.splice(i, 0, key);
        added = true;
        break;
      }
    }
    if (!added) {
        sorted.push(key);
    }
  }
  return sorted.reverse();
}

var pairs = [mp('vote_140_prof','announce_140_prof'),mp('vote_140_prof','first_day_of_classes'),mp('dev_shed_algo','vote_140_prof'),mp('dev_shed_algo','do_hair'),mp('do_hair','big_meeting'),mp('big_meeting','first_day_of_classes'),mp('announce_140_prof','first_day_of_classes')];
console.log(sortEvents(pairs));

事情可能无法正常工作的一个原因是您的测试数据的大小写不一致。本次运行的结果是:

Array [ "School", "EatFood", "CutHair", "Meeting", "BrushTeeth", "DoHair" ]

我将在您的其他数据集上对其进行测试,但我相信这可以满足提示。一会儿我会写下它的工作原理。

请注意,这不会执行任何文件 IO 或读取行。它将sortEvents 的输入作为具有startend 属性的对象数组,我提供了一个帮助方法makePair 来创建它们。

该解决方案的工作原理是构建一个字典,其中包含哪些元素先于哪些元素。

如果你有这样的输入:

a->b
c->a
c->b
b->d

字典应该是这样的:

a->[c],
c->[],
b->[a,c],
d->[b]

然后我们使用一个数组作为一种链表,我们检查它是否需要插入一些东西。例如,如果我们试图查看应该在哪里插入a 并且列表是c,那么我们将查看c 的字典,看到c 在其中,然后我们知道在a之前应该有c,因此我们必须在c之后插入a

【讨论】:

  • 我不认为这是正确的顺序,DoHair 应该是第二个,你的代码说 EatFood 是第二个,我也尝试了另一个测试用例,但顺序混淆了。我将仔细研究您的解决方案,也许您遗漏了一些小东西?
  • 我在这里找到了测试用例的链接potw.quinnftw.com/problem/2015/6
  • 没有一个正确的答案。许多不同的答案可以满足约束。该算法提供了一个正确的答案。 DoHair 的唯一规范是它在会议之前 -> 它是。
  • 实际上,我意识到我的错误是,刷牙也以两种不同的方式大写,这意味着它的位置很奇怪。
  • DoHair 是在会之前,会是在刷牙之前,eatfood 是在刷牙之前,还有 cuthair,但 school 是在吃之前
【解决方案3】:

从第一个事件开始,将其值设置为 0,而不是在遇到事件 2 时检查事件 1 的值,而不是为事件 2 设置较小的值。一旦完成按值排序哈希。

宾果游戏

line = input();
myMap = dict()
i=0
while i < line:
        event1 = raw_input()
        event2 = raw_input()
        if event1 in myMap :
                myMap[event2] = myMap[event1]+1
        elif event2 in myMap:
                myMap[event1] = myMap[event2]-1
        else :
                myMap[event1] = 0
                myMap[event2] = 1
        i=i+1
        print i
        print myMap

我不知道为什么有些人投反对票,但它确实有效,至少在你的两个样本上

示例输入和输出

6
eatfood
cuthair
1
{'eatfood': 0, 'cuthair': 1}
eatfood
brushteeth
2
{'brushteeth': 1, 'eatfood': 0, 'cuthair': 1}
school
eatfood
3
{'brushteeth': 1, 'eatfood': 0, 'school': -1, 'cuthair': 1}
school
dohair
4
{'brushteeth': 1, 'eatfood': 0, 'school': -1, 'cuthair': 1, 'dohair': 0}
dohair
meeting
5
{'school': -1, 'brushteeth': 1, 'cuthair': 1, 'dohair': 0, 'eatfood': 0, 'meeting': 1}
meeting
brushteeth
6
{'school': -1, 'brushteeth': 2, 'cuthair': 1, 'dohair': 0, 'eatfood': 0, 'meeting': 1}

代码是python,可以用javascript转换

【讨论】:

  • 请在单独的行中提供 event1 和 event2,而不是用空格分隔
  • 它看起来很不错,知道如何在 javascript 中使用吗?我真的无法按照你的程序进行
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-07-31
  • 2019-06-30
  • 1970-01-01
  • 1970-01-01
  • 2019-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多