[KMOI R1] 军事行动题解
Fire_flame · · 题解
\mathtt{Solution}
其实题目描述是来迷惑你的(
因为每一次可以从任意已攻占的城市出发,所以相当于是求最小生成树。
我们可以用 bfs 马走日求出每两个点之间的边权。然后再跑一遍最小生成树即可。
但是 bfs 的时候,每一个点入队的时候就要标记为走过,如果等到遍历到这个点的时候再标记就晚了。
时间复杂度
标程一(bfs + kruskal):
#include<bits/stdc++.h>//By Fire_flame
using namespace std;
const int MAXN = 3e3 + 5, MR = 9e6 + 5, MN = 2e2 + 5;
int n, m, cnt, ans, mp[MN][MN], f[MN][MN], fa[MAXN];
struct edge{
int x, y, len;
bool operator < (const edge &ll)const{
return len < ll.len;
}
}e[MR];
struct node{
int x, y;
bool operator < (const node &rr)const{
if(x != rr.x)return x < rr.x;
return y < rr.y;
}
}a[MAXN];
struct step{
int x, y, len;
};
int dx[] = {-1, 1, 2, -2, -1, 1, 2, -2};
int dy[] = {2, 2, 1, 1, -2, -2, -1, -1};
void bfs(int sx, int sy){
queue<step>q;
q.push({sx, sy, 0});
memset(f, 0, sizeof(f));
f[sx][sy] = 1;
while(!q.empty()){
int tx = q.front().x, ty = q.front().y, tl = q.front().len;
q.pop();
for(int i = 0;i < 8;i ++){
int px = tx + dx[i], py = ty + dy[i];
if(f[px][py] || px <= 0 || py <= 0 || px > m || py > m)continue;
if(mp[px][py])e[++ cnt] = {mp[sx][sy], mp[px][py], tl + 1};
f[px][py] = 1;
q.push({px, py, tl + 1});
}
// printf("%d %d %d\n", tx, ty, tl);
}
}
int find(int u){
if(fa[u] == u)return u;
return fa[u] = find(fa[u]);
}
int main(){
scanf("%d%d", &n, &m);
for(int i = 1;i <= n;i ++)scanf("%d%d", &a[i].x, &a[i].y);
sort(a + 1, a + n + 1);
for(int i = 1;i <= n;i ++)mp[a[i].x][a[i].y] = fa[i] = i;
for(int i = 1;i <= n;i ++)bfs(a[i].x, a[i].y);
sort(e + 1, e + cnt + 1);
for(int i = 1;i <= cnt;i ++){
int tx = e[i].x, ty = e[i].y, tl = e[i].len;
if(find(tx) != find(ty)){
fa[find(tx)] = find(ty);
ans += tl;
}
}
printf("%d", ans + n - 1);
return 0;
}
标程二(bfs + prim):
#include <bits/stdc++.h>//代码提供者:康立扬
using namespace std;
int n;
int x,y,diss[310][310],u,v,vis[310][310],dis[4010],ans,N,a[310][310];
pair<int,int> q1[202500];int hd,tl;
struct node{
int u,dis;
bool operator<(const node &a) const{
return dis>a.dis;
}
};
int fx[8]={-1,1,2,-2,-1,1,2,-2};
int fy[8]={2,2,1,1,-2,-2,-1,-1};
struct point{
int x,y;
}c[4010];
void bfs(int x,int y){
hd=0,tl=0;
q1[tl++]={x,y};
for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) vis[i][j]=0;
diss[x][y]=1;
vis[x][y]=1;
int cnt=1;
while(hd<tl){
pair<int,int>u=q1[hd++];
//cout<<"~~"<<u.first<<" "<<u.second<<" "<<diss[u.first][u.second]<<"\n";
if(cnt==n) break;
for(int i=0;i<8;i++){
pair<int,int>v={u.first+fx[i],u.second+fy[i]};
//cout<<"to"<<v.first<<" "<<v.second<<"\n";
if(vis[v.first][v.second]||v.first<1||v.second<1||v.first>N||v.second>N) continue;
diss[v.first][v.second]=diss[u.first][u.second]+1;
vis[v.first][v.second]=1;
if(a[v.first][v.second]) cnt++;
q1[tl++]=v;
}
}
}
priority_queue<node>q;
void prim(){
dis[0]=0;
q.push({0,0});
while(!q.empty()){
int u=q.top().u,d=q.top().dis;
q.pop();
if(d!=dis[u]) continue;
ans+=d;
//cout<<u<<" "<<d<<"\n";
dis[u]=0;
bfs(c[u].x,c[u].y);
for(int i=0;i<n;i++){
if(diss[c[i].x][c[i].y]<dis[i]){
dis[i]=diss[c[i].x][c[i].y];
q.push({i,dis[i]});
}
}
}
}
int main(){
scanf("%d",&n);
memset(dis,0x3f,sizeof dis);
scanf("%d",&N);
for(int i=0;i<n;i++){
scanf("%d%d",&u,&v);
c[i].x=u,c[i].y=v;
a[u][v]=1;
}
prim();
printf("%d\n",ans);
return 0;
}