【CodeChef】Prison Escape(最短路)

题目大意:

给出一个01矩阵,求每个0移动(每次可以向有公共边的格子移动一步)到矩阵边界至少要经过多少个1。


考虑建最短路模型,将矩阵中的每个位置拆分为入点和出点,矩阵外部设为一个点。

枚举矩阵中的每个位置:

  • 如果这个位置在矩阵边界,矩阵外部向这个位置的入点连一条长度为0的边。
  • 如果这个位置是上的数是1,这个位置的入点向这个位置的出点连一条长度为1的边(否则长度为0)。
  • 枚举这个位置上下左右的位置,如果后者存在,则前者的出边向后者的入边连一条长度为0的边。

然后以矩阵外部为源点运行Dijkstra算法,即可得到每个0移动到矩阵边界至少要经过多少个1(为源点到此位置对应点最短路的长度)。

#include<bits/stdc++.h>
#define pt printf(">>>")
#define mid (((l)+(r))/2)
using namespace std;
typedef long long ll;
const ll N=3e5+10,inf=1e18+10,mod=1e9+7;
const ll dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
vector<pair<ll,ll> > G[N*2];
ll n,m;
char s[N],t[N];
ll d[N*2];
bool vis[N*2];
ll id(ll x,ll y){return (x-1)*m+y-1;}
void addedge(ll u,ll v,ll w){G[u].push_back(make_pair(v,w));}
void dijkstra(){
	priority_queue<pair<ll,ll>,vector<pair<ll,ll> >,greater<pair<ll,ll> > > que;
	for(ll i=0;i<=n*m*2;i++)d[i]=inf,vis[i]=false;
	d[2*n*m]=0;
	que.push(make_pair(0ll,2*n*m));
	while(que.size()){
		ll u=que.top().second;que.pop();
		if(vis[u])continue;
		vis[u]=true;
		for(ll i=0;i<G[u].size();i++){
			ll v=G[u][i].first,w=G[u][i].second;
			if(d[v]>d[u]+w){
				d[v]=d[u]+w;
				que.push(make_pair(d[v],v));
			}
		}
	}
}
int main(){
	int T;
	cin >> T;
	while(T--){
		cin >> n >> m;
		for(ll i=0;i<=2*n*m;i++)G[i].clear();
		s[0]='\0';
		for(ll i=1;i<=n;i++){
			cin >> t;
			strcat(s,t);
		}
		for(ll i=1;i<=n;i++){
			for(ll j=1;j<=m;j++){
				if(i==1||j==1||i==n||j==m)addedge(2*n*m,id(i,j),0);
				addedge(id(i,j),n*m+id(i,j),s[id(i,j)]=='1'?1:0);
				for(ll dd=0;dd<4;dd++){
					ll nx=i+dir[dd][0],ny=j+dir[dd][1];
					if(nx<1||nx>n||ny<1||ny>m)continue;
					addedge(n*m+id(i,j),id(nx,ny),0);
				}
			}
		}
		dijkstra();
		ll ans=0;
		for(ll i=0;i<n*m;i++)if(s[i]=='0')ans=max(ans,d[i]);
		cout << ans << endl;
	}
	return 0;
}
posted @ 2024-05-16 15:45  Alric  阅读(8)  评论(0编辑  收藏  举报