今回は実際に機能するかどうかを説明する新しいアルゴリズム。
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`);
}
オンラインでお試しください!
他の方法と同じ方法で実行します。
アルゴリズムの概要:
プログラムは最初にデータをCityクラスにマップし、Cityクラスはいくつかのデータポイントをマップします。
- city-都市の絶対距離
- left-左に最も近い都市の距離
- right-右に最も近い都市の距離
- index-(非推奨)元の都市配列のインデックス
次に、配列は以下を含むGroupクラスにスローされます。
- city-都市配列
- dist-グループにまたがる距離
- max-グループ内の最大の左接続
- スプリット()
- グループの中心都市に接続されている最大の接続に沿って分割されたサブグループを含む配列を返します
- 2つの中央ノード(偶数の長さのグループ)がある場合、それらの3つの接続から選択します
- (*注*:これにより、都市が2つ未満のグループが削除されます)
- センター()
- グループに最適なワイヤ値を返します
- このステップに残った各都市の繰り返しをスキップするソリューションに取り組んでいます
- マッピングが50%減少しました
これで、配置する発電所が2つ以上ある限り、アルゴリズムはグループの分割に進みます。
最後に、グループをそのセンターにマップし、それらをすべて合計します。
実行方法:
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の上限を指定できますか?