M N
a1,1 a2,1 ・・・ aM,1
a1,2 a2,2 ・・・ aM,2
・
・
・
a1,N a2,N ・・・ aM,N
ai,jは、盤面のi行目j列目を指し、表ならば0, 裏ならば1である。
1 <= M,N <= 8
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static string InputPattern = "Input1";
static List<string> GetInputList()
{
var WillReturn = new List<string>();
if (InputPattern == "Input1") {
WillReturn.Add("5 5");
WillReturn.Add("0 0 1 1 1");
WillReturn.Add("0 0 1 1 1");
WillReturn.Add("1 1 0 1 1");
WillReturn.Add("1 1 1 0 0");
WillReturn.Add("1 1 1 0 0");
//2
//4行目2列目と2行目4列目の2マスをひっくり返すのが最短手順である
}
else if (InputPattern == "Input2") {
WillReturn.Add("4 4");
WillReturn.Add("0 0 0 0");
WillReturn.Add("0 1 1 0");
WillReturn.Add("0 1 1 0");
WillReturn.Add("0 0 0 0");
//16
}
else if (InputPattern == "Input3") {
WillReturn.Add("8 5");
WillReturn.Add("0 0 1 1 1");
WillReturn.Add("0 0 1 1 1");
WillReturn.Add("0 1 0 0 1");
WillReturn.Add("1 0 0 1 0");
WillReturn.Add("1 1 1 0 0");
WillReturn.Add("1 0 1 0 1");
WillReturn.Add("0 1 0 0 1");
WillReturn.Add("0 0 1 1 1");
//5
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static int UB_X;
static int UB_Y;
struct JyoutaiDef
{
internal int CurrX;
internal int CurrY;
internal int Cost;
internal bool[,] MasuArr;
}
static void Main()
{
List<string> InputList = GetInputList();
int[] wkArr = { };
Action<string> SplitAct = pStr =>
wkArr = pStr.Split(' ').Select(X => int.Parse(X)).ToArray();
SplitAct(InputList[0]);
int M = wkArr[0], N = wkArr[1];
UB_X = N - 1;
UB_Y = M - 1;
bool[,] mQuestionArr = new bool[UB_X + 1, UB_Y + 1];
for (int I = 1; I <= InputList.Count - 1; I++) {
SplitAct(InputList[I]);
for (int J = 0; J <= wkArr.GetUpperBound(0); J++) {
mQuestionArr[J, I - 1] = (wkArr[J] == 1);
}
}
var Stk = new Stack<JyoutaiDef>();
JyoutaiDef WillPush;
WillPush.CurrX = WillPush.CurrY = 0;
WillPush.Cost = 0;
WillPush.MasuArr = mQuestionArr;
Stk.Push(WillPush);
int AnswerCost = int.MaxValue;
bool FoundAnswer = false;
while (Stk.Count > 0) {
JyoutaiDef Popped = Stk.Pop();
if (IsOK(Popped.MasuArr)) {
FoundAnswer = true;
AnswerCost = Popped.Cost;
continue;
}
//下限値枝切り
if (AnswerCost <= Popped.Cost) continue;
if (Popped.CurrY == UB_Y + 1) {
continue;
}
//次の座標を設定
WillPush.CurrY = Popped.CurrY;
WillPush.CurrX = Popped.CurrX + 1;
if (WillPush.CurrX == UB_X + 1) {
WillPush.CurrY++;
WillPush.CurrX = 0;
}
bool WillPushHanten = false; //反転させるケース
bool WillPushNonHanten = false; //反転させないケース
if (Popped.CurrY == 0) { //Y座標が0の場合
WillPushHanten = WillPushNonHanten = true;
}
else { //Y座標が1以上の場合
var wkList = new List<bool>();
//X=UB_Xなら、真上と左上
if (Popped.CurrX == UB_X) {
wkList.AddRange(DeriveBoolList(Popped.MasuArr, Popped.CurrX, Popped.CurrY - 1));
wkList.AddRange(DeriveBoolList(Popped.MasuArr, Popped.CurrX - 1, Popped.CurrY - 1));
}
else { //X<UB_Xなら、左上
wkList.AddRange(DeriveBoolList(Popped.MasuArr, Popped.CurrX - 1, Popped.CurrY - 1));
}
if (wkList.Count == 0) {
WillPushHanten = WillPushNonHanten = true;
}
else if (wkList.TrueForAll(A => A)) { //全部1の場合
WillPushHanten = true;
}
else if (wkList.TrueForAll(A => A == false)) { //全部0の場合
WillPushNonHanten = true;
}
}
if (WillPushHanten) { //反転させるケースをPush
WillPush.Cost = Popped.Cost + 1;
WillPush.MasuArr = (bool[,])Popped.MasuArr.Clone();
HantenSyori(WillPush.MasuArr, Popped.CurrX, Popped.CurrY);
Stk.Push(WillPush);
}
if (WillPushNonHanten) { //反転させないケースをPush
WillPush.Cost = Popped.Cost;
WillPush.MasuArr = Popped.MasuArr;
Stk.Push(WillPush);
}
}
if (FoundAnswer)
Console.WriteLine(AnswerCost);
else Console.WriteLine("Impossible");
}
//終了判定
static bool IsOK(bool[,] pMasuArr)
{
foreach (bool EachBool in pMasuArr) {
if (EachBool) return false;
}
return true;
}
//指定した座標のBool型のListを返す
static List<bool> DeriveBoolList(bool[,] pMasuArr, int pX, int pY)
{
if (pX < 0 || UB_X < pX) return new List<bool>();
if (pY < 0 || UB_Y < pY) return new List<bool>();
return new List<bool>() { pMasuArr[pX, pY] };
}
//押したマスと8近傍の、座標を反転
static void HantenSyori(bool[,] pMasuArr, int pX, int pY)
{
MasuHanten(pMasuArr, pX - 1, pY - 1);
MasuHanten(pMasuArr, pX - 1, pY);
MasuHanten(pMasuArr, pX - 1, pY + 1);
MasuHanten(pMasuArr, pX, pY - 1);
MasuHanten(pMasuArr, pX, pY);
MasuHanten(pMasuArr, pX, pY + 1);
MasuHanten(pMasuArr, pX + 1, pY - 1);
MasuHanten(pMasuArr, pX + 1, pY);
MasuHanten(pMasuArr, pX + 1, pY + 1);
}
//指定マスの0と1の反転
static void MasuHanten(bool[,] pMasuArr, int pX, int pY)
{
if (pX < 0 || UB_X < pX) return;
if (pY < 0 || UB_Y < pY) return;
pMasuArr[pX, pY] = !pMasuArr[pX, pY];
}
}