새로운 알고리즘, 이번에는 실제로 작동하는지 설명합니다.
const {performance} = require('perf_hooks');
class Connection{
constructor(left,index,length,right){
if(typeof right === 'undefined'){
this._distance = 0;
} else {
this._distance = typeof left === 'undefined' ? 0 :
Math.abs(right - left);
}
var half = Math.floor(length/2);
if(length % 2 < 1){
this._magnitude = half - Math.abs(index - half + 1);
} else {
var temp = index - half;
this._magnitude = half - Math.abs(temp >= 0 ?temp:temp + 1);
}
this._value = this.distance * this.magnitude;
}
get distance(){return this._distance;};
get magnitude(){return this._magnitude;};
set magnitude(value){
this._magnitude = value;
this._value = this.distance * this.magnitude;
};
valueOf(){return this._value};
}
class Group{
constructor(...connections){
this._connections = connections;
this._max = Math.max(...connections); //uses the ValueOf to get the highest Distance to the Left
}
get connections(){return this._connections;};
get max(){return this._max;};
cutLeft(index){
for(let i=1,j=index-1;;i++){
if(typeof this.connections[j] === 'undefined' || this.connections[j].magnitude <= i){
break;
}
this.connections[j].magnitude = i;
j--;
}
}
cutRight(index){
for(let i=0,j=index;;i++){
if(typeof this.connections[j] === 'undefined' || this.connections[j].magnitude <= i){
break;
}
this.connections[j].magnitude = i;
j++;
}
}
static of(...connections){
return new Group(...connections.map((c,i)=>new Connection(c.distance,i,connections.length)));
}
split(){
var index = this.connections.findIndex(c=>c.valueOf() == this.max);
if(index < 0){
return;
}
var length = this.connections.length;
var magnitude = this.connections[index].magnitude;
this.cutLeft(index);
this.cutRight(index);
this._max = Math.max(...this.connections);
}
center(){
if(typeof this._center === 'undefined'){
this._center = this.connections.reduce((a,b)=>a==0?b.valueOf():a.valueOf()+b.valueOf(),0);
}
return this._center;
}
valueOf(){return this._max;};
toString(){
var index = this.connections.findIndex(c=>c.valueOf() == this.max);
var value = this.connections[index].magnitude;
var ret = '';
for(let i = 0;i<value;i++){
ret += this.connections.map(c=>{return (i<c.magnitude)?c.distance:' ';}).reduce((a,b)=>a==''?b:a+'-'+b,'') + '\n';
}
return ret;
};
}
function crunch(plants, cities){
var found = [];
var size = cities.length;
cities = cities.map((city,i,arr)=> new Connection(city,i,size,arr[i+1])).slice(0,cities.length-1);
var group = new Group(...cities);
for(;plants>1;plants--){
group.split();
}
console.log(`Wire Length Needed: ${group.center()}`);
}
function biggestGroup(groups){
return groups.find(g => g[g.length-1].orig - g[0].orig);
}
function* range (start, end, limit) {
while (start < end || typeof limit !== 'undefined' && limit-- > 0) {
yield start
start += 1 + Math.floor(Math.random()*100);
}
}
function* cities (score){
let n = Math.floor(Math.pow(2,score/5));
var start = 0;
while (n-- > 0 && start <= (1000 * n)) {
yield start;
start += 1 + Math.floor(Math.random()*100);
}
}
if(typeof process.argv[3] === 'undefined'){
crunch(1,[0, 2, 4, 6, 8]);
console.log("Correct Answer: 12");
crunch(3,[0, 1, 10, 11, 20, 21, 22, 30, 32]);
console.log("Correct Answer: 23");
crunch(5,[0, 1, 3, 6, 8, 11, 14]);
console.log("Correct Answer: 3");
crunch(6,[0, 1, 3, 6, 8, 14, 15, 18, 29, 30, 38, 41, 45, 46, 49, 58, 66, 72, 83, 84]);
console.log("Correct Answer: 49");
crunch(2, [0, 21, 31, 45, 49, 54]);
console.log("Correct Answer: 40");
crunch(2, [0, 4, 7, 9, 10]);
console.log("Correct Answer: 7");
crunch(2, [0, 1, 3, 4, 9]);
console.log("Correct Answer: 6");
var max = 0;
var min = Number.POSITIVE_INFINITY;
var avg = [];
var score = typeof process.argv[2] === 'undefined' ? 60 : process.argv[2];
for(j = 0; j<10; j++){
var arr = []; for(let i of cities(score)) arr.push(i);
var plants = Math.floor(1 + Math.random() * arr.length);
console.log(`Running: Test:${j} Plants: ${plants}, Cities ${arr.length}, Score: ${score}`);
// console.log(`City Array: [${arr}]`);
var t0 = performance.now();
crunch(plants,arr);
var t1 = performance.now();
time = (t1-t0)/1000;
console.log(`Time Taken = ${time} seconds`);
avg.push(time);
max = Math.max(time,max);
min = Math.min(time,min);
}
console.log(`Bench: ${avg.reduce((a,b)=>a+b,0)/avg.length} Max: ${max} Min: ${min} Total: ${avg.reduce((a,b)=>a+b,0)}`);
} else {
var plants = process.argv[2];
var arr = process.argv.slice(3);
console.log(`Running: Plants: ${plants}, Cities ${arr.length}`);
var t0 = performance.now();
crunch(plants,arr);
var t1 = performance.now();
time = (t1-t0)/1000;
console.log(`Time Taken = ${time} seconds`);
}
온라인으로 사용해보십시오!
다른 것과 같은 방식으로 실행하십시오.
알고리즘의 개요 :
이 프로그램은 먼저 데이터를 도시 클래스에 매핑하고 몇 가지 데이터 포인트를 매핑합니다.
- 도시-도시의 절대 거리
- left-가장 가까운 도시와 왼쪽의 거리
- 오른쪽-가장 가까운 도시와 오른쪽의 거리
- index-원래 도시 배열의 (더 이상 사용되지 않는) 인덱스
그런 다음 배열은 다음과 같은 Group 클래스로 전달됩니다.
- 도시-도시 배열
- dist-그룹에 걸친 거리
- max-그룹에서 가장 큰 왼쪽 연결
- 스플릿()
- 그룹의 중심 도시에 연결된 가장 큰 연결을 따라 분할 된 하위 그룹을 포함하는 배열을 반환합니다.
- 2 개의 중심 노드 (짝수 그룹)가있는 경우 3 개의 연결 중에서 선택합니다.
- (* 참고 * : 도시가 2 개 미만인 그룹은 삭제됩니다)
- 센터()
- 그룹에 가장 적합한 와이어 값을 반환합니다
- 이 단계에서 남은 각 도시에 대한 반복을 건너 뛰는 솔루션 작업
- 이제 50 % 더 적은 매핑
이제 알고리즘은 두 개 이상의 발전소가있는 한 그룹을 분할합니다.
마지막으로 그룹을 중앙에 매핑하고 모두 합산합니다.
실행하는 방법 :
Node.js를 사용하여 실행 (v9.2.0은 작성에 사용 된 것임)
점수 70에 대해 생성 된 테스트 케이스를 사용하여 프로그램 실행 :
node program.js 70
1 개의 발전소와 도시를 사용하여 프로그램 실행 [0,3,5] :
node program.js 1 0 3 5
암호:
const {performance} = require('perf_hooks');
class City{
constructor(city, left, right, i){
this._city = city;
this._index = i;
this._left = typeof left === 'undefined' ? 0 : city - left;
this._right = typeof right === 'undefined' ? 0 : right - city;
}
get city(){return this._city;};
get index(){return this._index;};
get left(){return this._left;};
get right(){return this._right;};
set left(left){this._left = left};
set right(right){this._right = right};
valueOf(){return this._left;};
}
class Group{
constructor(...cities){
this._cities = cities;
// console.log(cities.map(a=>a.city).reduce((a,b)=>a===''?a+(b<10?' '+b:b):a+'-'+(b<10?' '+b:b),""));
// console.log(cities.map(a=>a.left).reduce((a,b)=>a===''?a+(b<10?' '+b:b):a+'-'+(b<10?' '+b:b),""));
// console.log(cities.map(a=>a.right).reduce((a,b)=>a===''?a+(b<10?' '+b:b):a+'-'+(b<10?' '+b:b),""));
// console.log("+==+==+==+==+==+==+==+==+==+==+==+==")
this._dist = cities[cities.length-1].city - cities[0].city;
this._max = Math.max(...cities); //uses the ValueOf to get the highest Distance to the Left
}
get dist(){return this._dist;};
get cities(){return this._cities;};
get max(){return this._max;};
split(){
//var index = this.cities.findIndex(city=>city.left == this.max);
//this.cities[index].left = 0;
// console.log(`Slicing-${this.max}-${index}------`)
var centerIndex = this.cities.length / 2;
var splitIndex = Math.floor(centerIndex);
if(centerIndex%1 > 0){
var center = this.cities[splitIndex];
if(center.right > center.left){
splitIndex++;
}
} else {
var right = this.cities[splitIndex];
var left = this.cities[splitIndex-1];
if(left.left > Math.max(right.right,right.left)){
splitIndex--;
} else if(right.right > Math.max(left.left,left.right)){
splitIndex++;
}
}
// console.log(splitIndex);
this.cities[splitIndex].left = 0;
this.cities[splitIndex-1].right = 0;
var leftCities = [...this.cities.slice(0,splitIndex)];
var rightCities = [...this.cities.slice(splitIndex)];
// var center = this.cities[]
if(leftCities.length <= 1){
if(rightCities.length <= 1){
return [];
}
return [new Group(...rightCities)]
}
if(rightCities.length <= 1){
return [new Group(...leftCities)];
}
return [new Group(...leftCities), new Group(...rightCities)];
}
center(){
if(typeof this._center === 'undefined'){
if(this.cities.length == 1){
return [0];
}
if(this.cities.length == 2){
return this.cities[1].left;
}
var index = Math.floor(this.cities.length/2);
this._center = this.cities.reduce((a,b)=> {
// console.log(`${a} + (${b.city} - ${city.city})`);
return a + Math.abs(b.city - this.cities[index].city);
},0);
// console.log(this._center);
}
return this._center;
}
valueOf(){return this._max;};
}
function crunch(plants, cities){
var found = [];
var size = cities.length;
cities = cities.map((city,i,arr)=> new City(city,arr[i-1],arr[i+1],i));
var groups = [new Group(...cities)];
// console.log(groups);
for(;plants>1;plants--){
var mapped = groups.map(g=>g.center()-g.max);
var largest = Math.max(...groups);
// console.log('Largest:',largest)
// console.log(...mapped);
var index = groups.findIndex((g,i)=> mapped[i] == g.center() - g.max && g.max == largest);
// console.log(index);
groups = index == 0 ?
[...groups[index].split(),...groups.slice(index+1)]:
[...groups.slice(0,index),...groups[index].split(),...groups.slice(index+1)];
}
// console.log(`=Cities=${size}================`);
// console.log(groups);
size = groups.map(g=>g.cities.length).reduce((a,b)=>a+b,0);
// console.log(`=Cities=${size}================`);
var wires = groups.map(g=>g.center());
// console.log(...wires);
// console.log(`=Cities=${size}================`);
console.log(`Wire Length Needed: ${wires.reduce((a,b)=>a + b,0)}`);
}
function biggestGroup(groups){
return groups.find(g => g[g.length-1].orig - g[0].orig);
}
function* range (start, end, limit) {
while (start < end || typeof limit !== 'undefined' && limit-- > 0) {
yield start
start += 1 + Math.floor(Math.random()*100);
}
}
function* cities (score){
let n = Math.floor(Math.pow(2,score/5));
var start = 0;
while (n-- > 0 && start <= (1000 * n)) {
yield start;
start += 1 + Math.floor(Math.random()*100);
}
}
if(typeof process.argv[3] === 'undefined'){
crunch(1,[0, 2, 4, 6, 8]);
console.log("Correct Answer: 12");
crunch(3,[0, 1, 10, 11, 20, 21, 22, 30, 32]);
console.log("Correct Answer: 23");
crunch(5,[0, 1, 3, 6, 8, 11, 14]);
console.log("Correct Answer: 3");
crunch(6,[0, 1, 3, 6, 8, 14, 15, 18, 29, 30, 38, 41, 45, 46, 49, 58, 66, 72, 83, 84]);
console.log("Correct Answer: 49");
crunch(2, [0, 21, 31, 45, 49, 54]);
console.log("Correct Answer: 40");
crunch(2, [0, 4, 7, 9, 10]);
console.log("Correct Answer: 7");
var max = 0;
var min = Number.POSITIVE_INFINITY;
var avg = [];
var score = typeof process.argv[2] === 'undefined' ? 60 : process.argv[2];
for(j = 0; j<10; j++){
var arr = []; for(let i of cities(score)) arr.push(i);
var plants = Math.floor(1 + Math.random() * arr.length);
console.log(`Running: Test:${j} Plants: ${plants}, Cities ${arr.length}, Score: ${score}`);
var t0 = performance.now();
crunch(plants,arr);
var t1 = performance.now();
time = (t1-t0)/1000;
console.log(`Time Taken = ${time} seconds`);
avg.push(time);
max = Math.max(time,max);
min = Math.min(time,min);
}
console.log(`Bench: ${avg.reduce((a,b)=>a+b,0)/avg.length} Max: ${max} Min: ${min} Total: ${avg.reduce((a,b)=>a+b,0)}`);
} else {
var plants = process.argv[2];
var arr = process.argv.slice(3);
console.log(`Running: Plants: ${plants}, Cities ${arr.length}`);
var t0 = performance.now();
crunch(plants,arr);
var t1 = performance.now();
time = (t1-t0)/1000;
console.log(`Time Taken = ${time} seconds`);
}
온라인으로 사용해보십시오!
나는 여전히이 작업을 진행하면서 다음 며칠 동안 주석 처리 된 코드를 정리 할 것입니다. 단지 작은 경우 이상을 통과했는지 확인하고 싶었습니다.
2^^(x/5)
: 무엇을 의미 하는가 ? N에 대한 상한을 제공 할 수 있습니까?