J - Jailbreak Gym - 100625J -搜索+枚举交点

  • J - Jailbreak

  •  Gym - 100625J 
  • 题意:有两个犯人要逃出监狱,监狱中有很多门,打开一道门需要花费1的体力,
  • 当一个犯人打开门后另一个就不需要在打开了。走到地图外就算逃出监狱了。
  • ‘*’表示墙,‘.’表示路,‘#’表示门(花费1体力),问两个人都逃出去的最小花费,保证有解。
  • 思路:最初想到最优解应该是两个人最终汇于一点然后一起走出去花费最小,但是想到有特例两个人分别走自己的走出去
  • 为最优解也可能,比如两个人无法找到一个交点这一种情况就无法用找到公共交点来解决,但是只要把图的外面加一圈‘.’
  • 所有的就都连起来了,因为题目已说每个犯人都能逃脱,所以外面加上一圈‘.’后都能连通并且没有增加话费。
  • 所以这是所有情况都可以通过枚举两个人的交点来解决,因为最终他们都得出来。
  • 所需要增加一个外面的点(我选择的0,0)枚举一下这三个点在哪里交叉花费最小即可。
  • #include<bits/stdc++.h>
    using namespace std;
    #define inf 0x3f3f3f3f
    #define maxn 155
    bool vis[maxn][maxn];
    char mmp[maxn][maxn];
    int s[3][maxn][maxn];
    int t,n,m,x[3],y[3],c,ans;
    struct node
    {
        int x,y,door;
        bool operator<(const node&b)const
        {
            return door>b.door;
        }
    } top,temp;
    int to[5][2]= {{0,1},{0,-1},{1,0},{-1,0}};
    bool judge(int x,int y)
    {
        if(x<0||y<0||x>n+1||y>m+1||vis[x][y]||mmp[x][y]=='*')
            return false;
        return true;
    }
    void  bfs(int ord,int x,int y)
    {
        memset(vis,0,sizeof(vis));
        priority_queue<node>q;
        if(mmp[x][y]=='#')
            q.push(node{x,y,1});
        else
            q.push(node{x,y,0});
        vis[x][y]=1;
        while(!q.empty())
        {
            top=q.top();
            q.pop();
            s[ord][top.x][top.y]=top.door;
            for(int i=0; i<4; i++)
            {
                temp=top;
                temp.x=top.x+to[i][0];
                temp.y=top.y+to[i][1];
                if(judge(temp.x,temp.y))
                {
                    if(mmp[temp.x][temp.y]=='#')
                        temp.door++;
                    q.push(temp);
                    vis[temp.x][temp.y]=1;
                }
            }
        }
        return ;
    }
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            memset(s,inf,sizeof(s));
            ans=inf;
            c=x[0]=y[0]=0;
            scanf("%d%d",&n,&m);
            memset(mmp,'.',sizeof(mmp));
            for(int i=1; i<=n; i++)
            {
                getchar();
                for(int j=1; j<=m; j++)
                {
                    scanf("%c",&mmp[i][j]);
                    if(mmp[i][j]=='$')
                    {
                        x[++c]=i;
                        y[c]=j;
                    }
                }
            }
            for(int i=0; i<3; i++)
                bfs(i,x[i],y[i]);
            for(int i=0; i<=n; i++)
                for(int j=0; j<=m; j++)
                {
                    if(mmp[i][j]=='*'||s[0][i][j]==inf||s[1][i][j]==inf||s[2][i][j]==inf)continue;
                    if(mmp[i][j]=='#')
                        ans=min(ans,s[0][i][j]+s[1][i][j]+s[2][i][j]-2);
                    else
                        ans=min(ans,s[0][i][j]+s[1][i][j]+s[2][i][j]);
                }
            printf("%d\n",ans);
        }
        return 0;
    }

     

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值