个人牢骚(可以跳过):
这道纠结题,算起来,这道题好像是10几天前做的了吧。。中途有几天反复拿出来debug几个小时,每次都改进了一点点,但是还是WA。应该从最初的队列说起吧,还没有给start的方向跟拐角数赋值就匆匆慢慢地入队。好吧,这个好像检查了半个小时呢,自己的检查效率好低啊,暑假人真懒散。之后,debugOK了,哈哈,测试数据都过,心里那个激动啊,直接就submit,想不到TLE,好吧,我……。想了好久没有没到方法,好吧,又隔了几天,再拿出来晒晒的时候,发现原来可以用一个数组visited[]来标识每一个空格的最小转弯数。好吧,思路用上去了,可是还是错了,HDU给的sample都过,可以自己出了一个数据就不过。好吧,原来是自己在下面的输入判断两个元素是否能消掉的时候,忘记了每次都应该给visited[]初始化。。坑爹啊。
题意:
很清晰的题意,给你一个连连看的图,然后判断其中的任意两个元素能否消除。不过玩过连连看的朋友应该都知道,连连看是可以从地图外边连线消掉元素的,可是这道题目限定了不可以。这样反而会好做一点儿。
解题思路:
用bfs,用队列一层一层地搜下去,然后每一个点都用一个dir来表示这里走过的方向,当下一个点的方向跟这个点不同时,表示转角次数的corner要++。当corner大于2时,这个点就不能用了。此题要用一个visited[]数组来优化,visited用来计算每一个点的以前拐角的次数,初始化是INT_MAX(正无穷)。然后如果下次一个点的拐角次数比它的visited[]还要大,那么好吧,这个点就不用再入队了,没意思了,因为上次已经有一个拐角比它还要小得入队了(如果上次那个不能过,这个拐角比它大的还能过么?)。
(AC)代码:
#include<iostream> #include<queue> using namespace std; const int M=1005; //const int infinity=1000000000; int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};//方向 int map[M][M],rows,cols;//map为连连看中的各个点的标志,而mark为标志点是否已被走过 int visited[M][M]; struct Point { int x,y; int dir;//方向 int corner;//拐角的个数 }start,back; void bfs() { int i; Point pre,cur; visited[start.x][start.y]=0; start.dir=-1;//用-1来标志无方向 start.corner=0; /*这里要先改变值,然后才入队*/ queue<Point> que; que.push(start); while(!que.empty()) { pre=que.front();//队头出列 que.pop(); if(pre.x==back.x&&pre.y==back.y) { cout<<"YES"<<endl;//走到终点,就YES了 return ; } for(i=0;i<4;i++)//0上,1右,2下,3左 { cur.x=pre.x+dir[i][0];//当前点走的方向,方向总共有四个,所以这个for循环4次 cur.y=pre.y+dir[i][1]; cur.corner=pre.corner; cur.dir=pre.dir; if(pre.dir==-1)//如果pre点的方向为-1,那么此点为起始点 { cur.corner=0;//那么它的下一个点,自然无需增加拐角的个数 cur.dir=i; } else if(pre.dir!=i)//如果前一个点跟现在的点的方向不一样 { cur.corner++;//那么当前点的拐角要增加 cur.dir=i; } if(cur.x<1||cur.x>rows||cur.y<1||cur.y>cols)//超出连连看范围 continue; if(map[cur.x][cur.y]&&!(cur.x==back.x&&cur.y==back.y)||cur.corner>2) continue; if(visited[cur.x][cur.y]>cur.corner) { visited[cur.x][cur.y]=cur.corner; que.push(cur);//如果当前点还不是终点,那么应该将这个点入队 } } } cout<<"NO"<<endl; } void init() { for(int i=1;i<=rows;i++) for(int j=1;j<=cols;j++) visited[i][j]=INT_MAX; } int main(void) { int num,i,j; while(scanf("%d%d",&rows,&cols),rows||cols)//行列 { for(i=1;i<=rows;i++) for(j=1;j<=cols;j++) scanf("%d",&map[i][j]); scanf("%d",&num);//判断的个数 for(i=1;i<=num;i++) { scanf("%d%d%d%d",&start.x,&start.y,&back.x,&back.y); if(start.x==back.x&&start.y==back.y) { cout<<"NO"<<endl; continue; } //相同的起点&&终点||起点空||终点空 if((map[start.x][start.y]!=map[back.x][back.y])||!map[start.x][start.y]||!map[back.x][back.y]) { cout<<"NO"<<endl; continue; } init(); bfs();//广搜 } } return 0; } |