HDU1175 - 连连看 - 不好写

PS:这一题也是写了二十多遍了,去年这个时候写的,也是写了几天。过几天等考试结束了,集训的时候重新把几种方法再写一下!

题意:中文题,自行理解。

思路:

  1. 三维+优先队列写的,跑的时间是最短的,780ms。
  2. dfs+剪枝+判断方向是否改变。跑了辣么长时间6895ms。

PS:flag标记判断方向就行了。

三维+优先队列写的,跑的时间是最短的,780ms。


//三维+优先队列
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
int aaa[1100][1100];
int book[1100][1100][4];
int aa,bb,cc,dd;
int flag;
int n,m;
int dir[4][2]= {{1,0},{0,-1},{0,1},{-1,0}};
struct node
{
    int x;
    int y;
    int step;
    int to;
    // int qqq;
    bool operator < (const node &a)const
    {
        return a.step<step;
    }
} p,q;
void bfs(int a,int b,int c,int d)
{
    book[a][b][0]=1;
    priority_queue<node>Q;
    // queue<node>Q;

    p.x=a;
    p.y=b;
    p.step=0;
    p.to=-1;
    Q.push(p);

    while(!Q.empty())
    {
        //      q=Q.front();
        q=Q.top();
        Q.pop();
        for(int i=0; i<4; i++)
        {
            p=q;
            p.x+=dir[i][0];
            p.y+=dir[i][1];
            if(p.x>0&&p.x<=n&&p.y>0&&p.y<=m&&(aaa[p.x][p.y]==0||(p.x==cc&&p.y==dd))&&book[p.x][p.y][i]==0)
                //  if(p.x>0&&p.x<=n&&p.y>0&&p.y<=m&&book[p.x][p.y]==0&&(aaa[p.x][p.y]==0||(p.x==cc&&p.y==dd)))
            {
                book[p.x][p.y][i]=1;
                if(p.to!=i)
                {
                    if(p.step<=2)
                    {
                        p.step=q.step+1;
                        p.to=i;
                    }
                    else
                        continue;

                }
                else
                {
                    if(p.step<=3)
                    {
                        p.step=q.step;
                        p.to=i;
                    }
                }
                if(p.x==cc&&p.y==dd&&p.step<=3)
                {
                    flag=1;
                    return;
                }
                Q.push(p);
                //    Q.push(p);
            }
        }
    }
    return ;
}

int main()
{
    while(~scanf("%d %d",&n,&m)&&(n+m))
    {
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=m; j++)
            {
                scanf("%d",&aaa[i][j]);
            }
        }
        int ss;
        scanf("%d",&ss);
        while(ss--)
        {
            memset(book,0,sizeof(book));
            flag=0;
            scanf("%d %d %d %d",&aa,&bb,&cc,&dd);
            if((aaa[aa][bb]!=aaa[cc][dd])||aaa[aa][bb]==0||aaa[cc][dd]==0)
            {
                printf("NO\n");
                continue;
            }
            bfs(aa,bb,cc,dd);
            if(flag==0)
                printf("NO\n");
            else
                printf("YES\n");
        }
    }
    return 0;
}

dfs+剪枝+判断方向是否改变:

#include<stdio.h>
#include<string.h>
#define inf 0x3f3f3f3f

int a[1100][1100];
int book[1100][1100];
int flag,step,k;
int n,m;
int aa,bb,cc,dd;
int dir[4][2]= {{1,0},{-1,0},{0,1},{0,-1}};
void dfs(int x1,int y1,int to,int step)
{
    book[x1][y1]=1;
    //  if(k)return ;
    if(k||step>3)
        return ;//这里注意剪枝,否则step如果>3但是不满足下一个if语句的话,会进入下一个for循环,每次循环4次,数据大了会超时
    if(x1==cc&&y1==dd)
    {
        if(step<=3)//因为for循环里面进去的step如果是=3且方向改变的话,step会变成4不满足条件
        {
            k=1;
            return;
        }
    }

    int face;//判断转弯次数
    for(int i=0; i<4; i++)
    {
        int tx=x1+dir[i][0];
        int ty=y1+dir[i][1];
        if(tx>0&&tx<=n&&ty>0&&ty<=m&&book[tx][ty]==0&&step<=3&&(a[tx][ty]==0||(tx==cc&&ty==dd)))
        {
            //
            face=step;//****
            //控制每一次对于同一个点的四个方向搜的时候,原步数不变,否则每一步都在同一个点的上一步++了
            if(to!=i)//第一次方向肯定改变,因为需要保证步数++,所以后来满足条件的最大step是3
            {
                // to=i;//***
                face++;
            }
            else
            {
                to=to;
                step=step;//方向想等的时候转弯次数不变
            }
            book[tx][ty]=1;
            dfs(tx,ty,i,face);//递归不是to,是上次走的那个方向也就是i
            //第一次搜的时候第三个位置是to,因为要保证第一个step++
            book[tx][ty]=0;//取标
        }
    }
    return;
}

int main()
{
    while(~scanf("%d %d",&n,&m)&&(n+m))
    {

        memset(a,0,sizeof(a));
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=m; j++)
                scanf("%d",&a[i][j]);
        }
        int ss;
        scanf("%d",&ss);
        for(int i=0; i<ss; i++)
        {
            memset(book,0,sizeof(book));
            scanf("%d %d %d %d",&aa,&bb,&cc,&dd);
            if((a[aa][bb]!=a[cc][dd])||a[aa][bb]==0||a[cc][dd]==0)
            {
                printf("NO\n");
                continue;
            }
       //     book[aa][bb]=1;
            //-1判断方向是否改变
            k=0;
            dfs(aa,bb,-1,0);//只能去传入方向是否改变和转弯次数,不能传入坐标(无法记录方向是否改变)
            //只有第一次传入-1,之后传入的都是记录上一次的方向i
            if(k==1)
                printf("YES\n");
            if(k==0)
                printf("NO\n");
        }
    }
    return 0;
}
//4 4
//1 2 3 4
//0 0 0 0
//4 3 1 0
//0 0 1 0
//1
//1 1 4 3

猜你喜欢

转载自www.cnblogs.com/OFSHK/p/13179590.html