【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;
}