解法一:Kruskal算法
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2050;
const int M = N * N;
int n = 2021;
int m; //m代表任意两点间的可能边数之和
int p[N]; //记录城邦的编号
struct Edge{
int a, b, w; //(a, b)代表坐标(i,j), w代表权值
bool operator < (const Edge &t) const{
return w < t.w;
}
}edges[M];
int find(int x)
{
if (x != p[x])
p[x] = find(p[x]);
return p[x];
}
//最小生成树算法
int kruskal()
{
for (int i = 1; i <= n; ++ i )
p[i] = i;
sort(edges, edges + m); //按照费用进行升序排序
int res = 0; //res代表最少费用
int cnt = 0;
for (int i = 0; i < m; ++ i ) //遍历所有的点(即城邦编号)
{
int a = edges[i].a, b = edges[i].b, w = edges[i].w;
a = find(a), b = find(b);
if (a == b)
continue;
p[a] = b; //换成p[b] = a亦可
cnt ++;
res += w;
}
// cout<<"m = "<<m<<", cnt = "<<cnt<<endl; //在本题中,m = 2041210, cnt = 2020
return res;
}
//计算两个编号的不相等的各位数之和
int get(int x, int y)
{
int res = 0;
while (x || y)
{
if (x % 10 != y % 10)
res += x % 10 + y % 10;
x /= 10, y /= 10;
}
return res;
}
int main()
{
//n为城邦数量
for (int i = 1; i <= n; ++ i )
for (int j = i + 1; j <= n; ++ j ) //无向连通图只需用倒三角存储即可,减少了存储所需的空间
edges[m ++] = {i, j, get(i, j)};
int res = kruskal();
printf("%d\n", res); //res = 4046
for (int i = 1; i <= n; ++ i )
cout<<p[i]<<" ";
return 0;
}
解法二:Prim算法
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_set>
using namespace std;
const int N = 2050;
int n = 2021;
int g[N][N];
int dist[N];
bool st[N];
int prim()
{
memset(dist, 0x3f, sizeof dist);
int res = 0;
for (int i = 0; i < n; ++ i )
{
int t = -1;
for (int j = 1; j <= n; ++ j )
if (!st[j] && (t == -1 || dist[j] < dist[t]))
t = j;
if (i && dist[t] == 0x3f3f3f3f)
return dist[t];
if (i)
res += dist[t];
for (int j = 1; j <= n; ++ j )
dist[j] = min(dist[j], g[t][j]);
st[t] = true;
}
return res;
}
int get(int x, int y)
{
int res = 0;
while (x || y)
{
if (x % 10 != y % 10)
res += x % 10 + y % 10;
x /= 10, y /= 10;
}
return res;
}
int main()
{
memset(g, 0x3f, sizeof g); //设置g数组的每个元素的初始值为0x3f3f3f3f,在竞赛中通常使用这种方法表示最大值
for (int i = 1; i <= n; ++ i )
for (int j = i + 1; j <= n; ++ j )
g[i][j] = g[j][i] = get(i, j);
int res = prim();
printf("%d\n", res);
return 0;
}