背景:和poj1753一樣,用dfs就可以做出來,只是和1753相比較得輸出一些步驟,不過這也不麻煩,直接用兩個數組就可以存儲了。不過記住當遞歸回來的時候記住把數組裏面對應位置的元素清零。
思路:同上一篇1753.
#include <stdio.h>
#include <string.h>
int q[4][4],ok=0,r[16],c[16];
int iswin(void)
{
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
if(q[i][j]!=1) return 0;
return 1;
}
void change(int i,int j)
{
q[i][j]=!q[i][j];
for(int k=0;k<4;k++)
{
q[i][k]=!q[i][k];
q[k][j]=!q[k][j];
}
}
void dfs(int m,int sum,int a,int b)
{
if(ok) return;
else if(m==sum)
{
if(iswin())
{
ok=1;
printf("%d\n",sum);
for(int k=0;k<sum;k++)
printf("%d %d\n",r[k],c[k]);
}
else return;
}
else
{
for(int i=a;i<4;i++)
{
for(int j=b;j<4;j++)
{
r[m]=i+1;c[m]=j+1;
change(i,j);
if(j<3) dfs(m+1,sum,i,j+1);
else {dfs(m+1,sum,i+1,0);b=0;}
change(i,j);
r[m]=0;c[m]=0;
}
}
return;
}
}
int main(void)
{
char ch;
memset(r,0,sizeof(r));
memset(c,0,sizeof(c));
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
{
scanf("%c",&ch);
if(j==3) getchar();
q[i][j]=(ch=='+')?0:1;
}
if(iswin()) {printf("%d\n",0);return 0;}
for(int k=1;k<=16;k++)
{
dfs(0,k,0,0);
if(ok) break;
}
return 0;
}
在網上看到有這樣用遞歸的,感覺好高大上。
雖然他寫的代碼,我有一些地方不懂,不過這些都是我要學習的東西。
他的思路:
1.一個元素翻轉奇數次狀態不變,翻轉偶數次狀態改變
由1容易推到出2
2:要想把第Sij翻轉,同時保持第i行和第j列其他元素狀態不變,sij本身翻轉兩次,第i和第j列的其他元素翻轉一次.
由把所有狀態爲關的元素都做一次2操作,記錄那些元素狀態變化過,變化過的元素個數即最小步驟數.
由以上分析得出,各個元素的步驟順序其實是無所謂的.把變化的過元素按任意順序輸出即步驟.
附代碼:
#include <iostream>
#include <queue>
bool mark[4][4];
struct Pos
{
int x;
int y;
};
std::queue<Pos> Ans;
int input()
{
memset(mark,0,sizeof(mark));
int i ,j,k;
char ch;
for (i = 0 ;i < 4 ; ++ i)
{
for (j = 0 ;j < 4 ; ++j)
{
ch = getchar();
if ('+' == ch)
{
mark[i][j] = !mark[i][j];
for(k = 0 ; k < 4 ; k ++)
{
mark[i][k] = !mark[i][k];
mark[k][j] = ! mark[k][j];
}
}
}
getchar();
}
return 0;
}
int main()
{
int nStep = 0;
int i,j;
input();
for ( i = 0 ; i < 4; ++i)
{
for (j = 0 ; j < 4 ; ++j)
{
if (mark[i][j])
{
nStep ++;
Pos pos;
pos.x = i + 1;
pos.y = j + 1;
Ans.push(pos);
}
}
}
std::cout <<nStep<<std::endl;
while (!Ans.empty())
{
Pos pos = Ans.front();
Ans.pop();
std::cout<<pos.x<<" "<<pos.y<<std::endl;
}
return 0;
}