题意:N个点,给你N个点的坐标,现在还有Q条边已经连接好了。问把N个点怎么连接起来的花费的距离最短?
坑点:注意多组输入输出可能会超时。本题为:Special judgeYes,只要是符合要求的正确答案即可。
思路:prim或者kruskal的路径输出。
①prim,已经建好的边的权值设置为0。开一个pre数组//pre[i]记录距离i最近的点。那么建立的边也就为pre[i]和i,但是i节点不能是之前已经建立好的边,也就是dis[i]不能为0。
②kruskal,在输入的建好的边时候就把这两条边合并,然后统计建好了多少条边,还需要建立多少条边。
比如有4个点1,2,3,4,已经建好边有3条
1 2
2 1
3 1
此时还需要建立一条边,而不是还需要建立4 - 1 - 3 = 0条边 。
prim:
//#include<bits/stdc++.h>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
const int MAXN = 755;
const int INF = 0x3f3f3f3f;
int n, m, G[MAXN][MAXN];
struct Point
{
int x, y;
}point[MAXN];
void prim()
{
bool vis[MAXN];
int dis[MAXN], pre[MAXN];//pre[i]记录距离i最近的点
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n; i++)
{
dis[i] = G[1][i];
pre[i] = 1;
}
vis[1] = true;
for (int i = 1; i < n; i++)
{
int MIN = INF, pos;
for (int j = 1; j <= n; j++)
{
if (!vis[j] && dis[j] < MIN)
{
MIN = dis[j]; pos = j;
}
}
if(dis[pos] != 0) printf("%d %d\n",pre[pos], pos);//不是已经建好的路就输出当前建立的边
vis[pos] = true;
for (int j = 1; j <= n; j++)
{
if (!vis[j] && dis[j] > G[pos][j])
{
dis[j] = G[pos][j];
pre[j] = pos;
}
}
}
}
int main()
{
scanf("%d", &n);//多组会wa
{
for (int i = 1; i <= n; i++)
{
scanf("%d%d", &point[i].x, &point[i].y);
G[i][i] = 0;
for (int j = 1; j < i; j++)
{
G[i][j] = G[j][i] = (point[i].x - point[j].x) * (point[i].x - point[j].x) +
(point[i].y - point[j].y) * (point[i].y - point[j].y);
}
}
int Q;
scanf("%d", &Q);
while (Q--)
{
int a, b;
scanf("%d%d", &a, &b);
G[a][b] = G[b][a] = 0;
}
prim();
}
return 0;
}
/*
9
1 5
0 0
3 2
4 5
5 1
0 4
5 2
1 2
5 3
3
1 3
9 7
1 2
*/
kruskal:
//#include<bits/stdc++.h>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
const int MAXN = 755;
const int INF = 0x3f3f3f3f;
int n, m, cnt, f[MAXN];
struct Point
{
int x, y;
}point[MAXN];
struct Edge
{
int u, v, w;
bool operator < (const Edge& A) const
{
return w < A.w;
}
}edge[MAXN * MAXN];
int Find(int x) {return f[x] == x ? x : f[x] = Find(f[x]); }
bool Union(int a, int b)
{
int root1 = Find(a), root2 = Find(b);
if (root1 != root2)
{
f[root1] = root2;
return true;
}
return false;
}
void kruskal()
{
for (int i = 0; i < m; i++)
{
int u = edge[i].u, v = edge[i].v, w = edge[i].w;
if (Union(u, v))
{
printf("%d %d\n", u, v);
cnt++;
if (cnt == n -1 ) break;
}
}
}
int main()
{
scanf("%d", &n);//多组会wa
{
m = 0;
for (int i = 1; i <= n; i++)
{
scanf("%d%d", &point[i].x, &point[i].y);
for (int j = 1; j < i; j++)
{
edge[m].u = i;
edge[m].v = j;
edge[m++].w = (point[i].x - point[j].x) * (point[i].x - point[j].x) +
(point[i].y - point[j].y) * (point[i].y - point[j].y);
}
}
cnt = 0;//建好了0条边
for (int i = 0; i <= n; i++) f[i] = i;//并查集初始化
sort(edge, edge + m);//排序
int Q;
scanf("%d", &Q);
while (Q--)
{
int a, b;
scanf("%d%d", &a, &b);
if (Union(a, b)) cnt++;
}
kruskal();
}
return 0;
}
/*
9
1 5
0 0
3 2
4 5
5 1
0 4
5 2
1 2
5 3
3
1 3
9 7
1 2
*/