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;
}
posted @ 2024-03-07 13:16  harmis_yz  阅读(34)  评论(0)    收藏  举报