广搜优化题目总结

被刻印的时光 ゝ 提交于 2019-11-27 03:56:44

广搜优化题目总结

电路维修*

这道题之前打过,但那时候打题太水了,没有真正掌握这道题的知识点。(果然我还是太蒻了)

这道题的解法是先建边,对于每一个单位正方形,将有边相连的两个对角建一条长度为0的无向边,另外两个对角建一条长度为1的无向边。然后可以跑最短路或者用双端队列bfs(0-1bfs)。

跑最短路的话要注意由于是网格图spfa会炸掉,所以要用堆优化的dijkstra( ~~不会不加堆优化的dijkstra (^_^)~~ )

因为在练习广搜,所以我用的是双端队列bfs

当我们遇到边权只有1的情况时,显然直接bfs,然后第一次访问到某个点的“时间”就是到它的最短路径

当边权同时存在1和0两种情况时,我们就可以采用双端队列bfs,也叫作0-1bfs,就是访问时,若边权为0,则把目标点v放在队首,若边权为1,则把目标点放在队尾,这样是为了使得边权为0时的目标点v先被访问。

我按照这个思路做了,但却WA了,后来我一看题解,队列里维护的居然不是点,而是边,我一直想不通为什么,找了半天也只有题解模糊地写到,然后我就自己手玩了一把,发现如果是维护点,那么有可能会出现这样的情况:显然如果边权为0,那么目标点v与点u应该处于广搜的同一层,但如果是维护点,就可能会出现点v在被点u访问到之前被下一层的点提前访问了(也就是由这一层的点通过边权为1的边得到的目标点vv访问过来(因为如果是维护点,那么就会像是一个深搜的过程,会在我把这一层访问完之前,下一层的点先把这一层的点访问了))。但如果我们是维护边的话,那么将会起到一个滞留的作用,能够留给我时间,让我先把这一层的访问完了,在访问下一层。

这道题我还有一个收获就是知道了链式前向星还能储存入边,以前我的不知道来着,,,

这是我WA掉的访问点的代码(注释掉的是我手玩搜索过程的代码)

#include <iostream>
#include <queue>
#include <deque>
#include <cstdio>
#include <cstring>
using namespace std;
#define Maxn 280000
int n,m;
deque<int>q;
int fir[Maxn],nxt[Maxn*2],vv[Maxn*2],edg[Maxn*2];
int tot=0,ans=0;
int vis[Maxn],dis[Maxn];
void add(int u,int v,int w)
{
    nxt[++tot]=fir[u];
    fir[u]=tot;
    vv[tot]=v;
    edg[tot]=w;
}
//int room[1000];
int id(int x,int y){return (x-1)*(m+1)+y;}
void bfs()
{
    memset(dis,-1,sizeof(dis));
    q.push_front(id(1,1));vis[id(1,1)]=1;dis[id(1,1)]=0;
    while(!q.empty())
    {
   //    int cnt=0;
   //     printf("q:");
    //    while(!q.empty())
     //   {
     //       room[++cnt]=q.front();q.pop_front();
     //       printf("%d ",room[cnt]);
     //   }
     //   printf("\n");
      //       for(int i=cnt;i>=1;i--)q.push_front(room[i]);
        int u=q.front();q.pop_front();
     //   printf("u=%d dis[u]=%d\n",u,dis[u]);
        for(int i=fir[u];i;i=nxt[i])
        {
           // printf("u->v: %d->%d\n",u,vv[i]);
            int v=vv[i];
            if(vis[v]==1)continue;
            vis[v]=1;
            dis[v]=dis[u]+edg[i];
            if(v==id(n+1,m+1))return;
            if(edg[i]==0)q.push_front(v);
            else q.push_back(v);
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        string str;cin>>str;
        for(int j=1;j<=m;j++)
        {
            int x1=id(i,j),x2=id(i+1,j+1),y1=id(i+1,j),y2=id(i,j+1);
            if(str[j-1]=='/')
            {
                add(x1,x2,1);add(x2,x1,1);
                add(y1,y2,0);add(y2,y1,0);
            }
            else
            {
                add(x1,x2,0);add(x2,x1,0);
                add(y1,y2,1);add(y2,y1,1);
            }
        }
    }
    bfs();
 /*           for(int i=1;i<=n+1;i++)
        for(int j=1;j<=m+1;j++)
        printf("id(%d,%d)=%d\n",i,j,id(i,j));
    for(int i=1;i<=id(n+1,m+1);i++)
        printf("dis[%d]=%d\n",i,dis[i]);
    printf("id(n+1,m+1)=%d\n",id(n+1,m+1));printf("dis[%d]=%d\n",id(n+1,m+1),dis[id(n+1,m+1)]);*/
    if(dis[id(n+1,m+1)]==-1)printf("NO SOLUTION\n");
    else printf("%d\n",dis[id(n+1,m+1)]);
    return 0;
}

这是正解

#include <iostream>
#include <queue>
#include <deque>
#include <cstdio>
#include <cstring>
using namespace std;
#define Maxn 2800000
int n,m;
deque<int>q;
int fir[Maxn],nxt[Maxn*4],uu[Maxn*4],vv[Maxn*4],edg[Maxn*4];
int tot=0,ans=0;
int vis[Maxn],dis[Maxn];
void add(int u,int v,int w)
{
    nxt[++tot]=fir[u];
    fir[u]=tot;
    uu[tot]=u;
    vv[tot]=v;
    edg[tot]=w;
}
int id(int x,int y){return (x-1)*(m+1)+y;}
void bfs()
{
    memset(dis,-1,sizeof(dis));
    memset(vis,0,sizeof(vis));
    q.clear();
    q.push_front(id(1,1));vis[id(1,1)]=1;dis[id(1,1)]=0;
    while(!q.empty())
    {
        int e=q.front();q.pop_front();
        int u=uu[e];int v=vv[e];
        if(vis[v]==1)continue;
        vis[v]=1;
        dis[v]=dis[u]+edg[e];
        if(v==id(n+1,m+1))return;
        for(int i=fir[v];i;i=nxt[i])
        {
            if(vis[vv[i]]==1)continue;
            if(edg[i]==0)q.push_front(i);
            else q.push_back(i);
        }
    }
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        tot=0;memset(fir,0,sizeof(fir));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            string str;cin>>str;
            for(int j=1;j<=m;j++)
            {
                int x1=id(i,j),x2=id(i+1,j+1),y1=id(i+1,j),y2=id(i,j+1);
                if(str[j-1]=='/')
                {
                    add(x1,x2,1);add(x2,x1,1);
                    add(y1,y2,0);add(y2,y1,0);
                }
                else
                {
                    add(x1,x2,0);add(x2,x1,0);
                    add(y1,y2,1);add(y2,y1,1);
                }
            }
        }
        bfs();
        if(dis[id(n+1,m+1)]==-1)printf("NO SOLUTION\n");
        else printf("%d\n",dis[id(n+1,m+1)]);
    }
    return 0;
}

未完待续...

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!