poj2965(dfs暴力枚举)
原创
©著作权归作者所有:来自51CTO博客作者breakDawn的原创作品,请联系作者获取转载授权,否则将追究法律责任
题意:一个4*4的矩阵,只有+和-,每当对一个格子进行一次“改变”时,都会同时改变那一行和那一列的正负。问最少改变几次能变成全是-的矩阵,并给出改变的过程。
思路:和poj1753一样的思路,只要记住翻转顺序不影响结果,翻转2次和翻转0次是一样的,翻转3次和翻转1次是一样的,故问题就变成十六个格子里选几个格子进行改变。
#include<iostream>
#include<string>
using namespace std;
int ax[20],ay[20],map[6][6],m,bx[17],by[17],ans,limt;
void fan(int x,int y)
{
for(int i=1;i<=4;i++) //对目标格子所在行和所在列进行翻转
{
map[x][i]=!map[x][i];
map[i][y]=!map[i][y];
}
map[x][y]=!map[x][y]; //在对目标格子翻一次,因为前面的循环中翻了2次
}
int jude() //判断是否全为“-”
{
int i,j;
for(i=1;i<=4;i++)
for(j=1;j<=4;j++)
if(map[i][j]!=1)
return 0;
return 1;
}
void dfs(int cur,int d)
{
int j;
if(jude()) {ans=cur;return ;} //如果全为负,给ans赋值,退出
if(16-d<limt-cur-1||cur+1>limt) return ; //如果“剩余的可选棋子比所需棋子少”或者“你已经转的棋子比上限大”
for(int i=d;i<16&&ans==-1;i++) //从上次转的棋子+1开始选择
{
fan(ax[i],ay[i]); //翻转
bx[cur+1]=ax[i];by[cur+1]=ay[i]; //将此点记入数组
dfs(cur+1,i+1); //cur+1即选择的格子数+1,i+1即下一次转的棋子要比这次多1开始选,避免重复
fan(ax[i],ay[i]); //记得翻回
}
}
int main()
{
int i,j,k;
char str;
memset(map,0,sizeof(map));
k=0;
for(i=1;i<=4;i++)
{
for(j=1;j<=4;j++)
{
scanf("%c",&str);
ax[k]=i; //ax和ay数组记录十六个坐标
ay[k++]=j;
if(str=='+')
map[i][j]=0;
else map[i][j]=1;
}
getchar();
}
ans=-1;
for(i=0;i<=16;i++)
{
limt=i; //上限,使选择格子数从0慢慢增,直到16个,避免dfs超时
dfs(0,0);
if(ans!=-1)
{
cout<<ans<<endl;
for(j=1;j<=ans;j++)
cout<<bx[j]<<" "<<by[j]<<endl;
return 0;
}
}
}