以下是使用JavaScript的解决方案:
var matrix=[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
];
function createMatrixDivs() {
for(var r=0; r<16; r++) {
for(var c=0; c<16; c++) {
var cell=document.createElement("div");
cell.style="border:1px solid blue;position:absolute;width:10px;height:10px;left:"+10*c+"px;top:"+10*r+"px;";
cell.id=r+","+c;
document.body.append(cell);
}
}
}
function drawMatrixDivs() {
for(var r=0; r<16; r++) {
for(var c=0; c<16; c++) {
document.getElementById(r+","+c).style.backgroundColor=(matrix[r][c]==0?"white":matrix[r][c]==1?"red":matrix[r][c]==2?"green":"gray");
}
}
}
function outline(w) {
for(var r1=0; r1<16; r1++) {
for(var c1=0; c1<16; c1++) {
if(matrix[r1][c1]==0) {
for(var r2=0; r2<16; r2++) {
for(var c2=0; c2<16; c2++) {
if(r2!=r1 && c2!=c1 && matrix[r2][c2]==1 && Math.round(Math.sqrt(Math.pow(r2-r1,2)+Math.pow(c2-c1,2)))<=w) {
matrix[r1][c1]=2;
}
}
}
}
}
}
drawMatrixDivs();
}
createMatrixDivs();
drawMatrixDivs();
outline(+prompt("Enter outline width: "));
绿色轮廓显示了与红色像素之间的曼哈顿距离小于或等于w像素的像素。
你希望测量欧几里得距离,找到那些与红色像素之间距离小于或等于w像素的像素。
虽然有点棘手,但你实际上可以在线性时间(O(width * height))内完成此操作。
第一遍扫描:创建一个新矩阵M[y][x],给出从(x,y)到红色像素的垂直距离,如果距离大于w,则为w + 1。 你可以通过沿每列向上和向下扫描来在线性时间内完成此操作。
第二遍扫描:从左到右依次扫描每一行。当M[y][x] ≤ w时,你可以将像素(x,y)和其右侧sqrt(w2-M[y][x]2)个像素涂成绿色。记住已经涂过的像素的最右边位置,并避免重新涂色已经完成的像素,这个过程也需要线性时间。从右到左执行相同的操作。
制作一个查找表,以避免一直计算sqrt(w2-M[y][x]2)。
由于@iAmOren很好心地提供了可工作的JavaScript代码,我会直接复制并修复它以使用更快的算法:
var matrix=[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
];
function createMatrixDivs() {
for(var r=0; r<16; r++) {
for(var c=0; c<16; c++) {
var cell=document.createElement("div");
cell.style="border:1px solid blue;position:absolute;width:10px;height:10px;left:"+10*c+"px;top:"+10*r+"px;";
cell.id=r+","+c;
document.body.append(cell);
}
}
}
function drawMatrixDivs() {
for(var r=0; r<16; r++) {
for(var c=0; c<16; c++) {
document.getElementById(r+","+c).style.backgroundColor=(matrix[r][c]==0?"white":matrix[r][c]==1?"red":matrix[r][c]==2?"green":"gray");
}
}
}
function outline(w) {
var M = matrix.map(function(row) {
return row.slice();
});
var x,y,d,i,s,e;
//PASS 1 - put vertical distances in M
for(x=0; x<16; x++) {
d=w+1;
for(y=0; y<16; y++) {
if (matrix[y][x]==1) {
d=0;
} else if (d<=w) {
++d;
}
M[y][x]=d;
}
d=w+1;
for(y=15; y>=0; y--) {
if (matrix[y][x]==1) {
d=0;
} else if (d<=w) {
++d;
}
if (M[y][x] > d) {
M[y][x] = d;
}
}
}
// Precalculate vertical distance -> horizontal span
var spans=[];
for (i=0; i<=w; ++i) {
spans[i] = Math.sqrt((w+0.3)*(w+0.3) - i*i)|0;
}
// PASS 2 fill every pixel within w
for(y=0; y<16; y++) {
e=-1;
for (x=0; x<16; ++x) {
d = M[y][x];
if (d<=w) {
s=Math.max(x,e);
e=Math.max(e,x+spans[d]);
for(; s<=e && s<16; ++s) {
matrix[y][s] = matrix[y][s]||2;
}
}
}
e=17;
for (x=15; x>=0; --x) {
d = M[y][x];
if (d<=w) {
s=Math.min(x,e);
e=Math.min(e,x-spans[d]);
for(; s>=e && s>0; --s) {
matrix[y][s] = matrix[y][s]||2;
}
}
}
}
drawMatrixDivs();
}
createMatrixDivs();
drawMatrixDivs();
outline(+prompt("Enter outline width: "));
var t=new Date();outline(3);console.log(new Date() - t);
)
结果似乎有些不同,但总体上目标已经实现了。
我仍然不明白为什么这被认为不是O(n^4),如果不是,那么我的代码为什么不是小于O(n^4)呢。 - iAmOren