Codeforces Round 442 (Div. 2) D. Olya and Energy Drinks

文章讨论了CodeforcesRound442分数赛第二部分的D题,题目涉及使用BFS(广度优先搜索)解决与能量饮料有关的图问题。作者指出原始的BFS解决方案时间复杂度为O(n·m·k),过于缓慢。通过优化,将未访问的单元格存储在集合中,并对每一行和每一列创建单独的集合,从而可以更快地找到可达的未访问单元格,降低了时间复杂度到O(n·m·log(n))。文章提供了两种BFS实现,一种使用优先队列,另一种是普通队列,后者在实践中可能更快。
摘要由CSDN通过智能技术生成

Codeforces Round 442 (Div. 2) D. Olya and Energy Drinks

Note, that bfs can find right answer, but works in O(n·m·k). It’s too slow.
We’ll store all not visited cells in set. For each row and column we’ll make own set. Now it’s easy to find all not visited cell which is reachable from vertex in O(cnt·log(n)), where cnt is number of this cells. Then summary it works in O(n·m·log(n)).

注意,bfs可以找到正确答案,但适用于O(n·m·k)。太慢了。
我们将在set中存储所有未访问过的单元格。对于每一行和每一列,我们将创建自己的集合。现在很容易找到从O(cnt·log(n))的顶点可以到达的所有未访问的单元格,其中cnt是该单元格的数量。然后总结为O(n·m·log(n))

优先队列的BFS
#include<bits/stdc++.h>
using namespace std;

typedef pair<int,int> PII;
typedef pair<int,PII> PIII;
const int N = 1010;

char g[N][N];
int d[N][N];

int n,m,k;
int sx,sy,ex,ey;

int bfs()
{
	if(sx==ex && sy==ey) return 0;
	
	int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
	memset(d,0x3f,sizeof d);
	priority_queue<PIII,vector<PIII>,greater<PIII>> Q;
	
	Q.push({0,{sx,sy}});
	d[sx][sy]=0;
	
	while(!Q.empty())
	{
		PIII t=Q.top();Q.pop();
		
		for(int i=0;i<4;i++)
			for(int j=1;j<=k;j++)
			{
				int x=t.second.first+dx[i]*j,y=t.second.second+dy[i]*j;
				if(x<1 || x>n || y<1 || y>m || g[x][y]=='#') break;
				if(d[x][y]>d[t.second.first][t.second.second]+1)
				{
					d[x][y]=d[t.second.first][t.second.second]+1;
					if(x==ex && y==ey) return d[x][y];
					Q.push({d[x][y],{x,y}});
				}
			}
	}
	
	return -1;
}

int main()
{
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++) cin>>(g[i]+1);
	
	cin>>sx>>sy>>ex>>ey;
	
	cout<<bfs();

    return 0;
}
普通的BFS (似乎比优先队列更快)
#include<bits/stdc++.h>
using namespace std;

typedef pair<int,int> PII;
const int N = 1010;

char g[N][N];
int d[N][N];

int n,m,k;
int sx,sy,ex,ey;

int bfs()
{
	if(sx==ex && sy==ey) return 0;
	
	int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
	memset(d,0x3f,sizeof d);
	queue<PII> Q;
	
	Q.push({sx,sy});
	d[sx][sy]=0;
	
	while(!Q.empty())
	{
		PII t=Q.front();Q.pop();
		for(int i=0;i<4;i++)
			for(int j=1;j<=k;j++)
			{
				int x=t.first+dx[i]*j,y=t.second+dy[i]*j;
				if(x<1 || x>n || y<1 || y>m || g[x][y]=='#') break;
				if(d[x][y]<d[t.first][t.second]+1) break;
				if(d[x][y]>d[t.first][t.second]+1)
				{
					d[x][y]=d[t.first][t.second]+1;
					if(x==ex && y==ey) return d[x][y];
					Q.push({x,y});
				}
			}
	}
	
	return -1;
}

int main()
{
	
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++) cin>>(g[i]+1);
	
	cin>>sx>>sy>>ex>>ey;
	
	cout<<bfs();

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wa_Automata

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值