Thuật toán mới, sẽ giải thích nếu nó thực sự hoạt động lần này.
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`);
}
Hãy thử trực tuyến!
Chạy giống như cách khác.
Sơ lược về thuật toán:
Chương trình trước tiên ánh xạ Dữ liệu vào Lớp Thành phố, ánh xạ một vài điểm dữ liệu:
- thành phố - khoảng cách tuyệt đối của thành phố
- bên trái - khoảng cách của thành phố gần nhất bên trái
- bên phải - khoảng cách của thành phố gần nhất bên phải
- chỉ mục - chỉ số (không dùng nữa) trong mảng thành phố ban đầu
mảng sau đó được ném vào lớp Nhóm, có các mục sau:
- thành phố - mảng thành phố
- dist - khoảng cách kéo dài nhóm
- tối đa - kết nối bên trái lớn nhất trong nhóm
- chia ()
- trả về một mảng chứa các nhóm phụ được phân chia dọc theo kết nối lớn nhất được kết nối với thành phố trung tâm trong nhóm
- nếu có 2 nút trung tâm (một nhóm độ dài chẵn) thì nó chọn từ 3 kết nối đó
- (* lưu ý *: điều này sẽ loại bỏ bất kỳ nhóm nào có ít hơn hai thành phố)
- trung tâm()
- trả về giá trị dây tốt nhất cho nhóm
- làm việc trên một giải pháp để bỏ qua việc lặp lại qua từng thành phố còn lại cho bước này
- bây giờ với ánh xạ ít hơn 50%
Bây giờ thuật toán tiến hành phân chia các nhóm miễn là có 2 nhà máy điện trở lên.
Cuối cùng, nó ánh xạ các nhóm đến trung tâm của nó và tổng hợp tất cả chúng lại.
Cách chạy:
Chạy bằng Node.js (v9.2.0 là những gì đã được sử dụng để tạo)
chạy chương trình bằng các trường hợp kiểm tra được tạo cho điểm 70:
node program.js 70
chạy chương trình sử dụng 1 nhà máy điện và thành phố [0,3,5]:
node program.js 1 0 3 5
Mã số:
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`);
}
Hãy thử trực tuyến!
Tôi sẽ dọn sạch mã nhận xét trong vài ngày tới vì tôi vẫn đang làm việc này, chỉ muốn xem liệu điều này có vượt qua nhiều hơn những trường hợp nhỏ không.
2^^(x/5)
: nghĩa là gì ? bạn chỉ có thể cung cấp một giới hạn trên cho N?