Mathematica 186 (жадный) и 224 (все комбинации)
Жадное решение
t=MorphologicalTransform;n@w_:=Flatten@w~Count~1
p_~w~q_:=n[p~t~Max]==n[q~t~Max]
g@m_:=Module[{l=m~Position~1,r,d=m},While[l!={},If[w[m,r=ReplacePart[d,#-> 0]&
[l[[1]]]],d=r];l=Rest@l];n@m-n@d]
Это выключает лишние огни один за другим. Если при выключенном свете освещение не уменьшается, этот свет можно устранить. Жадный подход очень быстр и может легко обрабатывать матрицы 15х15 и намного больше (см. Ниже). Он возвращает единичные решения, но неизвестно, является ли это оптимальным или нет. Оба подхода в версиях для гольфа возвращают количество неиспользованных огней. Подходы без игры в гольф также отображают сетки, как показано ниже.
Перед:

После:

Оптимальные решения с использованием всех комбинаций источников света (224 символа)
С благодарностью @ Clément.
Ungolfed версия с использованием всех комбинаций огней
fФорма морфологического преобразования, используемая в, sameCoverageQрассматривает как освещенный (значение = 1 вместо нуля) квадрат 3 x3, в котором находится каждый источник света. Когда источник света находится вблизи края фермы, только квадраты (меньше 9) в пределах границ ферма подсчитана. Перебега нет; Квадрат, освещенный несколькими лампами, просто горит. Программа выключает каждую лампу и проверяет, не уменьшается ли общее освещение на ферме. Если это не так, этот свет исчезает.
nOnes[w_]:=Count[Flatten@w,1]
sameCoverageQ[m1_,m2_]:=nOnes[MorphologicalTransform[m1,Max]]==
nOnes[MorphologicalTransform[m2,Max]]
(*draws a grid with light bulbs *)
h[m_]:=Grid[m/.{1-> Style[\[LightBulb],24],0-> ""},Frame-> All,ItemSize->{1,1.5}]
c[m1_]:=GatherBy[Cases[{nOnes[MorphologicalTransform[ReplacePart[Array[0&,Dimensions[m1]],
#/.{{j_Integer,k_}:> {j,k}-> 1}],Max]],#,Length@#}&/@(Rest@Subsets[Position[m1,1]]),
{nOnes[MorphologicalTransform[m1,Max]],_,_}],Last][[1,All,2]]
nOnes[matrix]считает количество помеченных ячеек Он используется для подсчета света, а также для подсчета освещенных клеток.
sameCoverageQ[mat1, mat2] проверяет, равно ли количество подсвеченных ячеек в mat1 числу подсвеченных ячеек в mat2.MorphologicalTransform [[mat] принимает матрицу источников света и возвращает матрицу ячеек, которые они освещают.
c[m1]берет все комбинации источников света от m1 и проверяет их на предмет покрытия. Среди тех, которые имеют максимальный охват, он выбирает те, которые имеют наименьшее количество лампочек. Каждый из них является оптимальным решением.
Пример 1:
Настройка 6x6
(*all the lights *)
m=Array[RandomInteger[4]&,{6,6}]/.{2-> 0,3->0,4->0}
h[m]

Все оптимальные решения.
(*subsets of lights that provide full coverage *)
h/@(ReplacePart[Array[0&,Dimensions[m]],#/.{{j_Integer,k_}:> {j,k}-> 1}]&/@(c[m]))

Гольф версия с использованием всех комбинаций огней.
Эта версия рассчитывает количество неиспользованных источников света. Он не отображает сетки.
c возвращает количество неиспользованных источников света.
n@w_:=Flatten@w~Count~1;t=MorphologicalTransform;
c@r_:=n@m-GatherBy[Cases[{n@t[ReplacePart[Array[0 &,Dimensions[r]],#
/.{{j_Integer,k_}:> {j,k}-> 1}],Max],#,Length@#}&/@(Rest@Subsets[r~Position~1]),
{n[r~t~Max],_,_}],Last][[1,1,3]]
n[matrix]считает количество помеченных ячеек Он используется для подсчета света, а также для подсчета освещенных клеток.
s[mat1, mat2] проверяет, равно ли количество подсвеченных ячеек в mat1 числу подсвеченных ячеек в mat2.t [[mat] берет матрицу источников света и возвращает матрицу ячеек, которые они освещают.
c[j]берет все комбинации источников света из j и проверяет их на предмет покрытия. Среди тех, которые имеют максимальный охват, он выбирает те, которые имеют наименьшее количество лампочек. Каждый из них является оптимальным решением.
Пример 2
m=Array[RandomInteger[4]&,{6,6}]/.{2-> 0,3->0,4->0};
m//Grid

Два источника света можно сохранить при одинаковом освещении. см]
2