【题意】
给定4*4的棋盘,每个位置上为"B"、"W"或" ",表示黑棋、白棋或空格。定义目标棋局为有一行、一列或一条对角线上有相同颜色的四个子。黑白交替下,开始时任意一方先下,求最少多少步能达到目标棋局。
【分析】
首先定义变量:
基本 q(1)wt[2][2]记录空格位置
(2)int p[4][4]记录值,黑棋存1,白棋存2,空格存0
哈希表 hash(1)long long data,存棋局的值,就是转化为10进制后存储
(2)next,邻接表存下个位
(3)has,这个位置的个数
LMT=100000009;
Hd[LMT]存哈希表头
本题要求最小步数达到目标棋局,可以用广搜,但是广搜容易爆空间,而且不大好写,那就用迭代加深搜索好了。
迭代加深搜索的实现
Int check(void)
{
横排判定;
纵列判定;
左上-右下对角线判定;//对角线上的(i,j)满足i=j
右上-左下对角线判定;//对角线上的(i,j)满足i+j=4+1=5
}
Void swap(&I,&j)
{
I^=j^=i^=j; //怎么写都一样的啦
}
Int update(int u,int tag) //把插入、查找、删除给放到一个过程,因为很多部分都相同
{
Int key=u%LM; //得到属于的集合
for (intk=hd[key];k;k=hash[k].next) //枚举数据
if(hash[k].data==u) //若等于
if(typ==2) return hash[k].has;//若为查找过程返回has
else
{
hash[k].has^=1; //has的状态改变
return1; //直接退出
}
if (typ^2) //如果不是查找过程,则说明是插入过程,因为删除过程必定在上面完成了
{
hash[++tot].data=u;
hash[tot].has=1;
hash[tot].next=hd[key];
hd[key]=tot; //插入
}
return 0; //返回0,满足查找的找不到
}
Int can(int x,int y) //判定坐标满不满足
{
Return x+1&&x<4&&y+1&&y<4;//0<=x,y<=3
}
Int DFS(int dep,int lmt,int turn) //dep存当前第几步,lmt存深度,turn存哪一方
{
if (dep==lmt)return check(); //若到达了目标深度则判断行不行
long longgt=get();
update(gt,0); //哈希表中插入当前状态
int d=0; //标记
for (inti=0;!d&&i<2;i++) //枚举哪个空格移动
for (intj=0;!d&&j<4;j++) //枚举往哪走
if(can(p.wt[i][0]+dx[j],p.wt[i][1]+dy[j],turn)) //若可以移动
{
intx=p.wt[i][0]+dx[j],y=p.wt[i][1]+dy[j]; //x,y记录移动后的位
swap(p.p[p.wt[i][0]][p.wt[i][1]],p.p[x][y]);
p.wt[i][0]+=dx[j];
p.wt[i][1]+=dy[j]; //交换
if(!update(get(),2)) d|=DFS(dep+1,lmt,(turn-1^1)+1);
//如果没有这个状态则继续DFS
p.wt[i][0]-=dx[j];
p.wt[i][1]-=dy[j];
swap(p.p[p.wt[i][0]][p.wt[i][1]],p.p[x][y]);//还原
}
update(gt,0); //从哈希表中删除当前状态
return d; //返回标记
}
Int main(void)
{
……
For (cnt=0;!DFS(0,cnt,0)&&!DFS(0,cnt,1);cnt++);
Printf("%d\n",cnt);
Return 0;
}代码比较长,所以说这道题是神级的水题也差不多了……
【代码】
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
const int LM=10000009;
const int dx[4]={0,0,-1,1};
const int dy[4]={-1,1,0,0};
struct A
{
int p[4][6];
int wt[2][2];
}p;
struct H
{
long longdata;
int next,has;
}hash[3000000];
int hd[LM],tot;
int cnt;
int check(void)
{
int d;
for (inti=0;i<4;i++)
{
d=1;
for (intj=1;j<4;j++)
if(p.p[i][j]^p.p[i][0]) {d=0;break;}
if (d)return 1;
}
for (inti=0;i<4;i++)
{
d=1;
for (intj=1;j<4;j++)
if(p.p[j][i]^p.p[0][i]) {d=0;break;}
if (d)return 1;
}
d=1;
for (inti=1;i<4;i++)
if(p.p[0][0]^p.p[i][i]) {d=0;break;}
if (d) return1;
d=1;
for (inti=1;i<4;i++)
if(p.p[0][4]^p.p[i][4-i]) {d=0;break;}
return d;
}
long long get(void)
{
long longsum=0,mtp=1;
for (inti=3;i+1;i--)
for (intj=3;j+1;j--)
sum+=mtp*p.p[i][j],mtp*=10;
return sum;
}
int update(long long u,int typ)
{
intkey=(int)(u%LM);
for (intk=hd[key];k;k=hash[k].next)
if(hash[k].data==u)
if(typ==2)
if(hash[k].has) return 1; else;
else
{
hash[k].has^=1;
return1;
}
if (typ^2)
{
hash[++tot].data=u;
hash[tot].has=1;
hash[tot].next=hd[key];
hd[key]=tot;
}
return 0;
}
int can(int x,int y,int turn)
{
returnx+1&&x<4&&y+1&&y<4&&p.p[x][y]==turn;
}
void swap(int &i,int &j)
{
i^=j^=i^=j;
}
int DFS(int dep,int lmt,int turn)
{
if (dep==lmt)return check();
long longgt=get();
update(gt,1);
int d=0;
for (inti=0;!d&&i<2;i++)
for (intj=0;!d&&j<4;j++)
if(can(p.wt[i][0]+dx[j],p.wt[i][1]+dy[j],turn))
{
intx=p.wt[i][0]+dx[j],y=p.wt[i][1]+dy[j];
swap(p.p[p.wt[i][0]][p.wt[i][1]],p.p[x][y]);
p.wt[i][0]+=dx[j];
p.wt[i][1]+=dy[j];
if(!update(get(),2)) d|=DFS(dep+1,lmt,(turn-1^1)+1);
p.wt[i][0]-=dx[j];
p.wt[i][1]-=dy[j];
swap(p.p[p.wt[i][0]][p.wt[i][1]],p.p[x][y]);
}
update(gt,0);
return d;
}
int main(void)
{
int c=0; chars;
for (inti=0;i<4;i++)
{
for (intj=0;j<4;j++)
{
scanf("%c",&s);
p.p[i][j]=(s=='B'?2:s=='W'?1:0);
}
scanf("\n");
}
for (inti=0;i<4;i++)
for (intj=0;j<4;j++)
if(!p.p[i][j]) p.wt[c][0]=i,p.wt[c++][1]=j;
for(cnt=0;!DFS(0,cnt,1)&&!DFS(0,cnt,2);cnt++);
printf("%d\n",cnt);
return 0;
}【小结】
(1)在发现审错题或方法不对时,要学会给程序进行调整,而不应该前功尽弃,完全否定。
(2)程序的共用思想,几个类似的过程放到一个过程去完成,达到化简的效果
(3)当用广搜发现空间很大或无法估计空间时,可以考虑迭代加深搜索。
原文地址:http://blog.csdn.net/u013598409/article/details/43924465