*题解:QOJ #17855. Crosslink
解析
考虑只要求指定的两边联通怎么做,发现可以建两个超级源点分别连上两条边上的所有点,分别从两个源点开始跑 Dijkstra,最后枚举网格中的所有点即可。虽然到达两个边的路径可能会重,但出现这种情况的点必定更劣,且更优的点必定能被考虑到,所以不用另外处理这种情况。
对于四边联通,可以将其看成是两个两边联通。于是不难想到建四个超级源点跑四次最短路,对于每个点,对所有两条边的组合处理出最小到达花费。但是接下来要选择两个点分别作为连接两个边的代表,并计算使得它们联通的花费,光是枚举点的复杂度就已经不能接受。
依旧考虑最短路,令 \(dis_{i,j}\) 表示联通块包含 \(i\) 且能到达的边界集合为 \(j\) 时的最小花费,以一个连接所有点的超级源点跑最短路即可。
时间复杂度 \(O(nm\log nm)\)。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 5;
typedef pair<int,int> pii;
int mp[N][N],dis1[4][N][N],vis[N][N];
int rev[N];
int n,m;
int xy[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
struct S{
int dis,x,y;
friend bool operator > (S a,S b){
return a.dis > b.dis;
}
};
void dij1(int dis[N][N],char c){
memset(vis,false,sizeof(vis));
memset(dis,127,sizeof(int) * N * N);
priority_queue<S,vector<S>,greater<S> > pq;
if(c == 'U'){
for(int i=1;i<=m;i++){
dis[1][i] = mp[1][i];
pq.push({dis[1][i],1,i});
}
}else if(c == 'D'){
for(int i=1;i<=m;i++){
dis[n][i] = mp[n][i];
pq.push({dis[n][i],n,i});
}
}else if(c == 'L'){
for(int i=1;i<=n;i++){
dis[i][1] = mp[i][1];
pq.push({dis[i][1],i,1});
}
}else if(c == 'R'){
for(int i=1;i<=n;i++){
dis[i][m] = mp[i][m];
pq.push({dis[i][m],i,m});
}
}
while(!pq.empty()){
int x = pq.top().x,y = pq.top().y;
pq.pop();
if(vis[x][y]) continue;
vis[x][y] = true;
for(int i=0;i<4;i++){
int nx = x + xy[i][0],ny = y + xy[i][1];
if(nx >= 1 && nx <= n && ny >= 1 && ny <= m){
if(dis[nx][ny] > dis[x][y] + mp[nx][ny]){
dis[nx][ny] = dis[x][y] + mp[nx][ny];
pq.push({dis[nx][ny],nx,ny});
}
}
}
}
}
bool vis2[N][N];
int dis2[6][N][N];
vector<int> v;
void dij2(int dis2[N][N]){
memset(vis2,false,sizeof(vis2));
priority_queue<S,vector<S>,greater<S> > pq;
for(int j=1;j<=n;j++){
for(int k=1;k<=m;k++){
pq.push({dis2[j][k],j,k});
}
}
while(!pq.empty()){
int x = pq.top().x,y = pq.top().y;
pq.pop();
if(vis2[x][y]) continue;
vis2[x][y] = true;
for(int i=0;i<4;i++){
int nx = x + xy[i][0],ny = y + xy[i][1];
if(nx >= 1 && nx <= n && ny >= 1 && ny <= m){
if(dis2[nx][ny] > dis2[x][y] + mp[nx][ny]){
dis2[nx][ny] = dis2[x][y] + mp[nx][ny];
pq.push({dis2[nx][ny],nx,ny});
}
}
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
freopen("crosslink.in","r",stdin);
freopen("crosslink.out","w",stdout);
cin>>n>>m;
for(int i=0;i<(1 << 4);i++){
if(__builtin_popcount(i) == 2){
rev[i] = v.size();
v.push_back(i);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char c;
cin>>c;
if(c >= 'A' && c <= 'Z'){
mp[i][j] = c - 'A' + 10;
}else{
mp[i][j] = c - '0';
}
}
}
dij1(dis1[0],'U');
dij1(dis1[1],'D');
dij1(dis1[2],'L');
dij1(dis1[3],'R');
for(int i=0;i<(int)v.size();i++){
int p1 = 0,p2 = 0;
int cnt = 0;
for(int j=0;j<4;j++){
if(v[i] & (1 << j)){
cnt++;
if(cnt == 2) p2 = j;
else p1 = j;
}
}
for(int j=1;j<=n;j++){
for(int k=1;k<=m;k++){
dis2[i][j][k] = dis1[p1][j][k] + dis1[p2][j][k] - mp[j][k];
}
}
}
for(int i=0;i<6;i++){
dij2(dis2[i]);
}
int res = 2e9;
for(int k=0;k<6;k++){
int l = rev[v[k] ^ (0b1111)];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int x = dis2[k][i][j] + dis2[l][i][j] - mp[i][j];
res = min(res,x);
}
}
}
cout<<res;
return 0;
}

浙公网安备 33010602011771号