JavaScript - 673 707 730 751
e=[],g=[],h=[],m=[],q=[];function r(){a=s,b=t;function d(d,A){n=a+d,p=b+A;c>e[n][p]&&(u=!1,v>e[n][p]&&(v=e[n][p],w=n,k=p))}c=e[a][b],u=!0,v=c,w=a,k=b;0!=a&&d(-1,0);a!=l&&d(1,0);0!=b&&d(0,-1);b!=l&&d(0,1);g[a][b]=w;h[a][b]=k;return u}function x(a,b,d){function c(a,b,c,k){g[a+b][c+k]==a&&h[a+b][c+k]==c&&(d=x(a+b,c+k,d))}d++;0!=a&&c(a,-1,b,0);a!=l&&c(a,1,b,0);0!=b&&c(a,0,b,-1);b!=l&&c(a,0,b,1);return d}y=$EXEC('cat "'+$ARG[0]+'"').split("\n");l=y[0]-1;for(z=-1;z++<l;)e[z]=y[z+1].split(" "),g[z]=[],h[z]=[];for(s=-1;s++<l;)for(t=-1;t++<l;)r()&&m.push([s,t]);for(z=m.length-1;0<=z;--z)s=m[z][0],t=m[z][1],q.push(x(s,t,0));print(q.sort(function(a,b){return b-a}).join(" "));
ผลการทดสอบ (โดยใช้ Nashorn):
$ for i in A B C D; do jjs -scripting minlm.js -- "test$i"; done
7 2
1
11 7 7
7 5 4
$
อาจมีปัญหาสแต็กสำหรับแผนที่ขนาด 5000 (แต่นั่นเป็นรายละเอียดการนำไปปฏิบัติ :)
แหล่งที่มาที่ไม่รู้จักจบสิ้นในความน่ากลัวทั้งหมด:
// lm.js - find the local minima
// Globalization of variables.
/*
The map is a 2 dimensional array. Indices for the elements map as:
[0,0] ... [0,n]
...
[n,0] ... [n,n]
Each element of the array is a structure. The structure for each element is:
Item Purpose Range Comment
---- ------- ----- -------
h Height of cell integers
s Is it a sink? boolean
x X of downhill cell (0..maxIndex) if s is true, x&y point to self
y Y of downhill cell (0..maxIndex)
Debugging only:
b Basin name ('A'..'A'+# of basins)
Use a separate array-of-arrays for each structure item. The index range is
0..maxIndex.
*/
var height = [];
var sink = [];
var downhillX = [];
var downhillY = [];
//var basin = [];
var maxIndex;
// A list of sinks in the map. Each element is an array of [ x, y ], where
// both x & y are in the range 0..maxIndex.
var basinList = [];
// An unordered list of basin sizes.
var basinSize = [];
// Functions.
function isSink(x,y) {
var myHeight = height[x][y];
var imaSink = true;
var bestDownhillHeight = myHeight;
var bestDownhillX = x;
var bestDownhillY = y;
/*
Visit the neighbors. If this cell is the lowest, then it's the
sink. If not, find the steepest downhill direction.
This would be the place to test the assumption that "If a cell
is not a sink, you may assume it has a unique lowest neighbor and
that this neighbor will be lower than the cell." But right now, we'll
take that on faith.
*/
function visit(deltaX,deltaY) {
var neighborX = x+deltaX;
var neighborY = y+deltaY;
if (myHeight > height[neighborX][neighborY]) {
imaSink = false;
if (bestDownhillHeight > height[neighborX][neighborY]) {
bestDownhillHeight = height[neighborX][neighborY];
bestDownhillX = neighborX;
bestDownhillY = neighborY;
}
}
}
if (x !== 0) {
// upwards neighbor exists
visit(-1,0);
}
if (x !== maxIndex) {
// downwards neighbor exists
visit(1,0);
}
if (y !== 0) {
// left-hand neighbor exists
visit(0,-1);
}
if (y !== maxIndex) {
// right-hand neighbor exists
visit(0,1);
}
downhillX[x][y] = bestDownhillX;
downhillY[x][y] = bestDownhillY;
return imaSink;
}
function exploreBasin(x,y,currentSize) {//,basinName) {
// This cell is in the basin.
//basin[x][y] = basinName;
currentSize++;
/*
Visit all neighbors that have this cell as the best downhill
path and add them to the basin.
*/
function visit(x,deltaX,y,deltaY) {
if ((downhillX[x+deltaX][y+deltaY] === x) && (downhillY[x+deltaX][y+deltaY] === y)) {
currentSize = exploreBasin(x+deltaX,y+deltaY,currentSize); //,basinName);
}
return 0;
}
if (x !== 0) {
// upwards neighbor exists
visit(x,-1,y,0);
}
if (x !== maxIndex) {
// downwards neighbor exists
visit(x,1,y,0);
}
if (y !== 0) {
// left-hand neighbor exists
visit(x,0,y,-1);
}
if (y !== maxIndex) {
// right-hand neighbor exists
visit(x,0,y,1);
}
return currentSize;
}
// Read map from file (1st argument).
var lines = $EXEC('cat "' + $ARG[0] + '"').split('\n');
maxIndex = lines.shift() - 1;
for (var i = 0; i<=maxIndex; i++) {
height[i] = lines.shift().split(' ');
// Create all other 2D arrays.
sink[i] = [];
downhillX[i] = [];
downhillY[i] = [];
//basin[i] = [];
}
// Everyone decides if they are a sink. Create list of sinks (i.e. roots).
for (var x=0; x<=maxIndex; x++) {
for (var y=0; y<=maxIndex; y++) {
if (sink[x][y] = isSink(x,y)) {
// This node is a root (AKA sink).
basinList.push([x,y]);
}
}
}
//for (var i = 0; i<=maxIndex; i++) { print(sink[i]); }
// Each root explores it's basin.
//var basinName = 'A';
for (var i=basinList.length-1; i>=0; --i) { // i-- makes Closure Compiler sad
var x = basinList[i][0];
var y = basinList[i][1];
basinSize.push(exploreBasin(x,y,0)); //,basinName));
//basinName = String.fromCharCode(basinName.charCodeAt() + 1);
}
//for (var i = 0; i<=maxIndex; i++) { print(basin[i]); }
// Done.
print(basinSize.sort(function(a, b){return b-a}).join(' '));
ฉันได้ผลการลดขนาดที่ดีขึ้นโดยการแยกวัตถุองค์ประกอบออกเป็นอาร์เรย์ที่แยกจากกันทำให้เป็นโลกาภิวัตน์ในทุกที่ที่เป็นไปได้และกอดผลข้างเคียง NSFW
ผลกระทบของการย่อขนาดโค้ด:
- 4537 ไบต์ไม่ จำกัด ขนาด
- 1180 ไบต์ บรรจุหีบห่อ
- 855 ไบต์, การเพิ่มประสิทธิภาพของผู้บรรจุหีบห่อ + มือ (ชื่อโกลบอล 1 ตัว)
- 751 ไบต์, Google ปิดคอมไพเลอร์ที่มี ADVANCED_OPTIMIZATIONS (NB มันทำให้ร่องรอย "คืน 0" เป็นรหัสที่ตายแล้ว)
- 730 bytes, การเพิ่มประสิทธิภาพด้วยมือโดยประมาท (ฉันไม่ได้เปลี่ยนแหล่งที่ไม่ได้ระบุดังนั้น NSFW)
- 707 ไบต์, การเพิ่มประสิทธิภาพด้วยมือที่ประมาทมากขึ้น (ลบการอ้างอิงทั้งหมดเพื่อจม []);
- 673 ไบต์ลบ "var" s ทั้งหมดปล่อยแฟล็ก Nashorn -strict
ฉันสามารถทำได้ใกล้ถึง 700 ไบต์โดยไม่ต้องแก้ไขรหัสย่อเล็กสุดถ้าฉันยินดีที่จะแก้ไขต้นฉบับ แต่ฉันไม่ได้เพราะฉันคิดว่าการปล่อยให้เป็น - จะให้มุมมองที่น่าสนใจจากจุดเริ่มต้น