2019国防科大校赛A Escape LouvreⅠ

https://ac.nowcoder.com/acm/contest/878/A

很好的bfs模拟题,记录一下

要对于每个人找到离它最近的出口,而且优先上边再优先左边的出口,那么就是从上到下,从左到右得把出口放进队列,然后进行bfs,一个位置只能进队列一次,这样就能知道每个位置要去哪个出口排队。

再把每个人到对应出口的时间记录下来,放到那个出口上。

再对每一个出口,先按时间把要出去的人进行排序,使用一个优先队列,来判断每一时刻力量最大的人出去,时间++

如果当前时间等于还没进来的最早的人(队首)的时间,那么就while进优先队列。

如果当前队首时间大于当前时间,且优先队列中没人了(这里一开始没加这个判断),那么就跳转时间

当时还有输出错了,我以为是有人没出去直接输出-1,而实际是对于不能出去的人输出-1,其他人还是输出逃出时间

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

int n,m,p;
int tx[5]={0,1,0,-1,0};
int ty[5]={0,0,1,0,-1};
int ans[maxl*maxl];
int dis[maxl][maxl];
struct peo
{
    int x,y,w;    
}a[maxl*maxl];
struct que
{
    int id,tm;
};
vector <que> ext[maxl][maxl];
struct pr
{
    int x,y;
    bool operator < (const pr &b)const
    {
        if(x==b.x)
            return y<b.y;
        return x<b.x;
    } 
}outto[maxl][maxl];
char ch[maxl][maxl];
queue <pr> q;
priority_queue <pr> priq;

inline void prework()
{
    for(int i=1;i<=n;i++)
        scanf("%s",ch[i]+1);
    for(int i=1;i<=p;i++)
    {
        scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
        ans[i]=-1;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            ext[i][j].clear();
}

inline bool cmp(const que &x,const que &y)
{
    if(x.tm==y.tm)
    {
        return a[x.id].w>a[y.id].w;
    }
    return x.tm<y.tm;
}

inline void mainwork()
{
    while(!q.empty()) q.pop();
    memset(dis,0x3f,sizeof(dis));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        if(ch[i][j]=='2')
        {
            q.push(pr{i,j});
            outto[i][j]=pr{i,j};
            dis[i][j]=0;
        }
    pr u;int xx,yy;
    while(!q.empty())
    {
        u=q.front();q.pop();
        for(int i=1;i<=4;i++)
        {
            xx=u.x+tx[i];yy=u.y+ty[i];
            if(xx>=1 && xx<=n && yy>=1 && yy<=m && ch[xx][yy]!='1')
            {
                if(dis[xx][yy]>dis[u.x][u.y]+1)
                {
                    dis[xx][yy]=dis[u.x][u.y]+1;
                    outto[xx][yy]=outto[u.x][u.y];
                    q.push(pr{xx,yy});
                }
            }
        }
    }
    int tm;
    for(int i=1;i<=p;i++)
    if(dis[a[i].x][a[i].y]<dis[0][0])
    {
        u=outto[a[i].x][a[i].y];
        tm=dis[a[i].x][a[i].y];
        ext[u.x][u.y].push_back(que{i,tm});
    }
    int l,k;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            l=ext[i][j].size();
            if(l==0) continue;
            sort(ext[i][j].begin(),ext[i][j].end(),cmp);    
            k=0;
            tm=0;
            while(!priq.empty()) priq.pop();
            do
            {
                if(k<l && ext[i][j][k].tm>tm && priq.empty())
                    tm=ext[i][j][k].tm;
                while(k<l && ext[i][j][k].tm==tm)
                {    
                    priq.push(pr{a[ext[i][j][k].id].w,ext[i][j][k].id});
                    k++;
                }
                u=priq.top();priq.pop();
                ans[u.y]=tm;
                tm++;
            }while(k<l || !priq.empty());
        }
}

inline void print()
{
    for(int i=1;i<=p;i++)
        printf("%d%c",ans[i],(i==p)?'\n':' ');
}

int main()
{
    while(~scanf("%d%d%d",&n,&m,&p))
    {
        prework();
        mainwork();
        print();
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值