最小生成树题。好久没写邻接矩阵了。题意:有n个村庄,编号为1~n。你需要建造一些道路使得任意两个村庄是连通的。比如A与B连通当且仅当A与B之间有一条道路或者A与C连通,B与C连通。现在已经建造好了一些道路,你的任务是尽可能使得建造的道路长度短并且让任意两个村庄连通。
我的解题思路:比较巧的最小生成树题了。没仔细看我还以为是什么双连通分量要缩点什么的算法。其实就是裸求最小生成树,只不过有一些路已经建造好了。
我的解题代码:Kruskal算法
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 111;
struct edge
{
int x, y;
int len;
};
int map[N][N]; //图的邻接矩阵
edge road[N*N];
int rdn; //未建造的道路数量
int father[N];
int n, m;
void InitRead();
void DataProcess();
int Find(int x);
void Union(int x, int y);
int Kruskal();
int Mycmp(const void *a, const void *b);
int main()
{
while (~scanf("%d", &n))
{
InitRead();
DataProcess();
}
return 0;
}
void InitRead()
{
rdn = 0;
for (int i=1; i<=n; ++i)
{
father[i] = i;
for (int j=1; j<=n; ++j)
{
scanf("%d", &map[i][j]);
}
}
scanf("%d", &m);
int a, b;
while (m--)
{
scanf("%d %d", &a, &b);
Union(a, b);
}
return;
}
void DataProcess()
{
for (int i=1; i<=n; ++i)
{
for (int j=1; j<i; ++j)
{
if (Find(i) != Find(j))
{
road[rdn].x = i;
road[rdn].y = j;
road[rdn++].len = map[i][j];
}
}
}
printf("%d\n", Kruskal());
return;
}
int Find(int x)
{
int z, y = x;
while (y != father[y])
{
y = father[y];
}
while (x != father[x])
{
z = father[x];
father[x] = y;
x = z;
}
return y;
}
void Union(int x, int y)
{
int fx = Find(x);
int fy = Find(y);
father[fx] = fy;
return;
}
int Kruskal()
{
qsort(road, rdn, sizeof(edge), Mycmp);
int ans = 0;
for (int i=0; i<rdn; ++i)
{
if (Find(road[i].x) != Find(road[i].y))
{
Union(road[i].x, road[i].y);
ans += road[i].len;
}
}
return ans;
}
int Mycmp(const void *a, const void *b)
{
return (*(edge *)a).len - (*(edge *)b).len;
}