个人牢骚(可以跳过):

       这道纠结题,算起来,这道题好像是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

 

 

 

 

posted on 2011-08-20 15:28  cchun  阅读(211)  评论(0编辑  收藏  举报