【发布时间】:2017-03-20 06:04:08
【问题描述】:
问题
在我们的团队签到后,我们会与 (n) 名参与者进行协调会议,涵盖各种(唯一命名的)主题。
目前,人们都在试图自我组织,而我们并没有最大限度地提高会议的并发性,和/或尽快释放团队成员以重返工作岗位。
我们在Google Spreadsheet 中保留了签到后所有协调会议的列表:
+-----------------------------------------------------------+
| Meetings |
+-----------------------------------------------------------+
| Topic A | Topic B | Topic C | Topic D | Topic E |
+-----------------------------------------------------------+
| Billy | JD | David | Tania | JB |
| Mel | Rowan | Emily | David | Fred |
| Tracey | Mike | | Mike | Tania |
| JB | Aaron | | Fred | |
| Luke | Billy | | | |
| Aaron | | | | |
| Michael | | | | |
+-----------------------------------------------------------+
作为一个起点,我有(肯定是非常低效的)代码迭代每个会议并返回一个没有参与者冲突的对数组。
main() 的示例输出,上面作为输入数据(不用担心所有代码都在下面):
[["Topic A","Topic C"],["Topic A","Topic D"],["Topic B","Topic C"],["Topic B","Topic E"],["Topic C","Topic E"]]
我需要什么
理想情况下,我需要一个解决方案,该解决方案返回一个数组,该数组按可能一次运行的大多数会议排序。 使用从main() 返回的对数组或使用电子表格中的数据作为输入的完全不同的方法。
在我的示例中,它会采用以下形式:
[[Topic B, Topic C, Topic E],[Topic A, Topic D]]
然后,我将在 Google 电子表格中按颜色对它们进行可视化分组,以便员工可以看到。
我试图创建一些代码 (main2()) 来减少基于互斥对的数组,但这是完全错误的。例如:该代码输出:
[["Topic A","Topic C","Topic B","Topic E"],"Topic D"]
...这是不正确的,因为 A 和 B 显然有冲突。 (当然,A 和 C,B 和 E 可以连续使用)。
我当前的代码
function onOpen () {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Meeting Tools')
.addItem('Compute Optimal Meeting Order', 'main')
.addToUi();
}
function main() {
var ss = SpreadsheetApp.getActive();
var sss = ss.getActiveSheet();
//var sss = ss.getSheetByName("Sheet3");
var data = sss.getDataRange().getValues();
var ui = SpreadsheetApp.getUi();
var meetings = {};
var pairs = [];
var objKey;
// Structuring data to obj
for (var x=0; x < sss.getLastColumn(); x++) {
for (var y=1; y < data.length; y++) {
if (y==1) {
objKey = data[y][x];
meetings[objKey] = [];
}
else if (data[y][x]) {
meetings[objKey].push(data[y][x]);
}
}
}
var keys = Object.keys(meetings).sort();
var loc;
// Starting with "A"
for (var m in meetings) {
if (!meetings.hasOwnProperty(m)) continue;
Logger.log("-----------------------------");
Logger.log("SCANNING: " + m);
Logger.log("-----------------------------");
loc = keys.indexOf(m);
// check A, B, C, D, E
for (var m2 = 0; m2 < keys.length; m2++) {
var pointer = (m2 + loc) % keys.length;
// DO NOT CHECK SAME MEETING
if (keys[pointer] == m) {
Logger.log("||||||||| WE ARE COMPARING OURSELVES: (" + keys[pointer] + "/" + m + "). SKIPPING!");
continue;
}
// FOR EACH PARTICIPANT OF CURRENT MEETING
for (var p = 0; p < meetings[m].length; p++) {
Logger.log("");
Logger.log(" >>> COMPARING " + keys[pointer]);
Logger.log(" >>> >>> " + meetings[m][p] + " " + (p+1) +"/"+meetings[m]. length);
// SEEK THE LOCATION OF THE MEETING PARTICIPANT IN THE NEXT MEETING
var testIndex = meetings[keys[pointer]].indexOf(meetings[m][p]);
// IF THE MEETING PARTICIPANT IS ALSO IN THE NEXT MEETING
if (testIndex > -1) {
Logger.log("We have a match! Meeting "+ m + " has participant " + meetings[m][p] + " which unfortunately clashes with meeting " + keys[ pointer]);
Logger.log("Therefore Meeting " + m + " cannot run at the same time as " + keys[pointer]);
Logger.log("We need to bail out of compairing against: " + keys[pointer ]);
// WE BAIL OUT AS WE HAVE A CLASH
break;
}
// IF THE MEETING PARTICIPANT IS NOT IN THE NEXT MEETING AND WE HAVE CHECKED EVERYONE. WE SHOULD BE GOOD.
else if (testIndex == -1 && p+1 == meetings[m].length) {
Logger.log("This looks to be clear!!! Adding to pair group.");
pairs.push([m,keys[pointer]]);
}
}//loop
} //loop
} //obj_loop
// Logger.log("FINAL TALLY: " + JSON.stringify(pairs));
Logger.log("FINAL TALLY (CLEANED): " + JSON.stringify(removeRepeats(pairs.sort()) ));
// ui.alert(JSON.stringify(removeRepeats(pairs.sort())));
// ss.toast(JSON.stringify(removeRepeats(pairs.sort())));
// debugger;
return removeRepeats(pairs.sort());
}
function main2(array) {
// DEBUG
// array = [["A","C"],["A","D"],["B","C"],["B","E"],["C","E"]];
// array = [["A","C"],["A","D"],["B","C"],["B","E"],["C","E"]];
array = main();
var holdingArr = [];
for (var i = array.length - 1; i >= 1; i--) {
//DEBUG
//var pair = ["Z","X"];
var pair = array[i];
if (arrayPairCheck([array[0]], pair)) {
holdingArr.push(pair);
array.pop(i);
}
else {
array[0] = array[0].concat(array[i]);
array.pop(i);
}
} //loop
if (holdingArr && holdingArr.length > 0) {
for (var j=0; j < holdingArr.length; j++) {
var checkIndex = holdingMeetingExistsInPair(array[0],holdingArr[j]);
if (checkIndex !== false) {
array.push(holdingArr[j][checkIndex]);
}
} //loop
}
// DEBUG
debugger;
Logger.log(JSON.stringify(array));
}
function holdingMeetingExistsInPair(arrayFirstIndexGroup,holdingArrPair) {
if (arrayFirstIndexGroup && arrayFirstIndexGroup.length > 0) {
if (arrayFirstIndexGroup.indexOf(holdingArrPair[0]) === -1) {
return 0;
}
if (arrayFirstIndexGroup.indexOf(holdingArrPair[1]) === -1) {
return 1;
}
}
return false;
}
function arrayPairCheck(array,pair) {
// DEBUG
// array = [["A","C"],["A","D"],["B","C"],["B","E"],["C","E"]];
// pair = ["Z","X"];
var seen = false;
if (array && array.length > 0) {
for (var i=0; i < array.length; i++) {
array[i].map(function(item,item2) {
if (item === pair[0] || item === pair[1]) {
seen = true;
return true;
}
});
} //loop
}
if (seen) { return true; } else { return false; }
}
// http://stackoverflow.com/questions/27734661/javascript-arrays-ab-ba
function removeRepeats(list) {
var i;
var b = [];
var _c = [];
for (i = 0; i < list.length; i++) {
var a = list[i].sort();
var stra = a.join("-");
if(_c.indexOf(stra) === -1) {
b.push(a);
_c.push(stra);
}
}
return b;
}
最后
我一直在阅读的一些关于拼凑理解的途径如下。我的代表太低,无法链接这些。有人可能会确认这是一个追求的方向?
Hopcroft–Karp 算法
感谢您花时间在这方面。
更新 1
对于以下情况,解决方案应正确地将会议顺序设置为:
1) W、X、Z
2)V,是的
+-----------------------------------------------------------+
| Meetings |
+-----------------------------------------------------------+
| Topic V | Topic W | Topic X | Topic Y | Topic Z |
+-----------------------------------------------------------+
| Billy | JD | David | Tania | JB |
| Mel | Rowan | Emily | David | Fred |
| Tracey | Mike | | Mike | |
| JB | | | Fred | |
| Luke | | | | |
| Aaron | | | | |
| Michael | | | | |
+-----------------------------------------------------------+
【问题讨论】:
-
我假设所有参与者都在开始时聚集在一起,并且每个参与者在其最后一次会议结束后立即被释放。你想减少所有参与者在他们被释放之前所花费的总时间吗?那么你不应该优化会议的最大并发性。如果这些并发会议都只绑定少数参与者,而大多数参与者正在等待随后安排的单个非并发会议怎么办?
标签: javascript algorithm sorting google-apps-script