Three States codeforces

7 篇文章 0 订阅
废话

记录一下遇到的第二个01bfs问题,01bfs和bfs的区别在于路径权值只有0和1,这个时候就优先搞权值为0的边,就用双端队列deque存储,如果边权为0,在前面插入,否则的话在后面插入,比正常跑bfs速度快很多

题目链接

https://ac.nowcoder.com/acm/problem/111125

题面

The famous global economic crisis is approaching rapidly, so the states of Berman, Berance and Bertaly formed an alliance and allowed the residents of all member states to freely pass through the territory of any of them. In addition, it was decided that a road between the states should be built to guarantee so that one could any point of any country can be reached from any point of any other State.
Since roads are always expensive, the governments of the states of the newly formed alliance asked you to help them assess the costs. To do this, you have been issued a map that can be represented as a rectangle table consisting of n rows and m columns. Any cell of the map either belongs to one of three states, or is an area where it is allowed to build a road, or is an area where the construction of the road is not allowed. A cell is called passable, if it belongs to one of the states, or the road was built in this cell. From any passable cells you can move up, down, right and left, if the cell that corresponds to the movement exists and is passable.
Your task is to construct a road inside a minimum number of cells, so that it would be possible to get from any cell of any state to any cell of any other state using only passable cells.
It is guaranteed that initially it is possible to reach any cell of any state from any cell of this state, moving only along its cells. It is also guaranteed that for any state there is at least one cell that belongs to it.

题目大意
  1. 给定一个n * m 的矩阵,其中有1 , 2 , 3组成的连通块,表示三个州,然后 · 表示可修建路,花费为1,#表示不可走,问最少花费多少,可是三个州联通
策略

最优的情况肯定是通过某一点向三个连通块的花费最小。这个点可能是三大连通块之一,可能是 · , 如果是三大联通快,就直接是dis1 + dis2 + dis3 , 否则的话, · 这个到三连通块的距离在最优的情况下,只有一个 · 这个点重复走了三次,那么只需要走一次,dis1 + dis2 + dis3 - 2 ,
最优情况下, 某个点到三大联通块的三条路径中唯一的交叉点一定是被枚举的某一点
那么我们就是求出每个点到三个连通块的距离,反过来从每个连通块求到所有点的最短距离,最后枚举一下所有点即可

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <map>
#include <list>
#include <queue>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <stack>
#include <set>
#include <deque>
#pragma GCC optimize(3 , "Ofast" , "inline")
using namespace std ;
#define ios ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0)
#define x first
#define y second
#define ls rt << 1
#define rs rt << 1 | 1
typedef long long ll ;
const double esp = 1e-6 , pi = acos(-1) ;
typedef pair<int , int> PII ;
const int N = 1010 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
int cinint(){  int t ; scanf("%d" , &t) ;  return t ;}
int cinll(){ll t ;scanf("%lld" , &t) ;return t ;}
char s[N][N] ;
int n , m ;
int d[4][2] = {1 , 0 , -1 , 0 , 0 , 1 , 0 , -1} ;
int dis[N][N][4] ;
void bfs(int t)
{
  deque<PII> q ;
  for(int i = 0 ;i < n ;i ++ )
   for(int j = 0 ;j < m ;j ++ )
   {
     dis[i][j][t] = INF ;
     if(s[i][j] == t + '0')
      q.push_front({i , j}) , dis[i][j][t] = 0 ;
   }
  while(q.size())
  {
     auto u = q.front() ;
     q.pop_front() ;
      for(int i = 0 ;i < 4 ;i ++ )
       {
         int tx = u.x + d[i][0] , ty = u.y + d[i][1] ;
         if(tx < 0 || ty < 0 || tx >= n || ty >= m || s[tx][ty] == '#') continue ;
         int w = s[tx][ty] == '.' ;
         if(dis[tx][ty][t] > dis[u.x][u.y][t] + w)
         {
           dis[tx][ty][t] = dis[u.x][u.y][t] + w ;
           if(w) q.push_back({tx , ty}) ;
           else q.push_front({tx , ty}) ;
         }
       }
  }
}
int work()
{
  n = cinint() , m = cinint() ;
  for(int i = 0 ;i < n ;i ++ ) scanf("%s" , s[i]) ;
  bfs(1) , bfs(2) , bfs(3) ;
  ll ans = 1e18 ;
  for(int i = 0 ;i < n ;i ++ )
   for(int j = 0 ;j < m ;j ++ )
   {

      ll res = 1ll * dis[i][j][1] + dis[i][j][2] + dis[i][j][3] ;
      if(s[i][j] == '.') res -= 2 ;
      ans = min(1ll * ans , res) ;
   }
  if(ans > n * m) puts("-1") ;
  else cout << ans << endl ;
  return 0 ;
}
int main()
{

  work() ;
  return 0 ;
}
/*
*/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值