P9709 [KMOI R1] 军事行动 题解
分析
对于这道题,首先暴力找出任意两座城市之间的最短路,跑 \(n\) 次 BFS 就行。这里 BFS 的时候可以直接求第 \(i\) 座城市的坐标 \((x_i,y_i)\) 到所有图上坐标的最短路,最后第 \(i\) 座城市到第 \(j\) 组城市的最短路就是 \((x_i,y_i)\) 到 \((x_j,y_j)\) 的最短路。
现在求出来每两座城市之间的最短路,不难想到题目求的就是这些城市通过连接成树的最小边权和。用 Kruskal 就行。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define re register
#define il inline
#define PII pair<int,pair<int,int>>
#define x first
#define y second
const int N=2001,M=151;
int n,m;
int dx[11]={-1,1,2,-2,-1,1,2,-2},dy[11]={2,2,1,1,-2,-2,-1,-1};
struct node{
int x,y,id;
}a[N];
int dis[M][M],vis[M][M],dist[N][N];
int fa[N];
struct tree{
int x,y,z;
}tr[N*N];int idx;
il void bfs(int s){
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
queue<PII> qu;
qu.push({0,{a[s].x,a[s].y}});
dis[a[s].x][a[s].y]=0;
while(!qu.empty()){
PII now=qu.front();qu.pop();
if(vis[now.y.x][now.y.y]) continue;
vis[now.y.x][now.y.y]=1;
for(re int i=0;i<8;++i){
int x=now.y.x+dx[i],y=now.y.y+dy[i];
if(x<=0||y<=0||x>m||y>m) continue;
if(dis[x][y]>now.x+1)
dis[x][y]=now.x+1,qu.push({now.x+1,{x,y}});
}
}
return ;
}
il bool cmp(tree a,tree b){return a.z<b.z;}
il int find(int x){return (fa[x]==x)?x:(fa[x]=find(fa[x]));}
il void solve(){
cin>>n>>m;
for(re int i=1;i<=n;++i) cin>>a[i].x>>a[i].y,a[i].id=i;
for(re int i=1;i<=n;++i){
bfs(i);
for(re int j=1;j<=n;++j)
dist[i][j]=dis[a[j].x][a[j].y];
}
int ans=0;
for(re int i=1;i<=n;++i)
for(re int j=i+1;j<=n;++j)
tr[++idx]={i,j,dist[i][j]+1};
sort(tr+1,tr+idx+1,cmp);
for(re int i=1;i<=n;++i) fa[i]=i;
for(re int i=1;i<=idx;++i){
int x=find(tr[i].x),y=find(tr[i].y);
if(x!=y) ans+=tr[i].z,fa[x]=y;
}
cout<<ans;
return ;
}
signed main(){
solve();
return 0;
}

浙公网安备 33010602011771号