洛谷2243 电路维修 广搜+双端队列优化

题目描述
题意不太容易说清楚,还是看链接吧。

题解:
首先感觉是广搜求最短路的题目。我一开始是没想好怎么建图的,感觉直接乱做复杂度好像很爆炸。这个题的建图还是有点巧妙的,建图方法是把格点看作是图上的点,原来的斜线看作是两点间连边权为0的边,每个格子除了原来的斜线的另一条对角线的两点之间连一条边权为1的边,表示需要进行一次旋转。

建好图之后可以开始bfs了,但是这样的复杂度不够优秀,我们使用了双端队列来代替原来广搜的队列,边权为0的边到达的点插入队首,边权为1的点到达的点插入队尾,这样保证了每个点被遍历到的次数是O(1)级别的,最后总复杂度便是O(r*c*t)的了。

代码:

#include <bits/stdc++.h>
using namespace std;

int T,r,c,hed[600010],cnt,q[600010],h,t,inq[500010],dis[500010];
char s[510][510];
struct node
{
    int to,next,dis;
}a[2000010];
inline void add(int from,int to,int dis)
{
//  cout<<from<<" "<<to<<" "<<dis<<endl; 
    a[++cnt].to=to;
    a[cnt].dis=dis;
    a[cnt].next=hed[from];
    hed[from]=cnt;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&r,&c);
        for(int i=1;i<=r;++i)
        scanf("%s",s[i]+1);
        for(int i=1;i<=cnt;++i)
        {
            a[i].to=0;
            a[i].next=0;
            a[i].dis=0;
        }
        cnt=0;
        memset(hed,0,sizeof(hed));
        for(int i=1;i<=r;++i)
        {
            for(int j=1;j<=c;++j)
            {
                if(s[i][j]=='/')
                {
                    add((i-1)*(c+1)+j+1,i*(c+1)+j,0);
                    add(i*(c+1)+j,(i-1)*(c+1)+j+1,0);
                    add((i-1)*(c+1)+j,i*(c+1)+j+1,1);
                    add(i*(c+1)+j+1,(i-1)*(c+1)+j,1);
                }
                else
                {
                    add((i-1)*(c+1)+j+1,i*(c+1)+j,1);
                    add(i*(c+1)+j,(i-1)*(c+1)+j+1,1);
                    add((i-1)*(c+1)+j,i*(c+1)+j+1,0);
                    add(i*(c+1)+j+1,(i-1)*(c+1)+j,0);
                }
            }
        }
        h=501*501+2;
        t=h;
        q[h]=1;
        memset(inq,0,sizeof(inq));
        memset(dis,0x3f,sizeof(dis));
        dis[1]=0;
        inq[1]=1;
        while(h<=t)
        {
            int x=q[h];
            inq[x]=0;
            for(int i=hed[x];i;i=a[i].next)
            {
                int y=a[i].to;
                if(dis[y]>dis[x]+a[i].dis)
                {
                    dis[y]=dis[x]+a[i].dis;
                    if(!inq[y])
                    {
                        if(a[i].dis==0)
                        {
                            q[h]=y;
                            --h;
                            inq[y]=1;
                        }
                        else
                        {
                            q[++t]=y;
                            inq[y]=1;
                        }
                    }
                }       
            }
            ++h;
        }
        if(dis[(r+1)*(c+1)]<=1e6)
        printf("%d\n",dis[(r+1)*(c+1)]);
        else
        printf("NO SOLUTION\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值