原题链接:http://poj.org/problem?id=1258
周四上了节数据结构终于知道何为最小生成树,晚上回寝,遂得此题!
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 29613 | Accepted: 11750 |
Description
Input
Output
Sample Input
4 0 4 9 21 4 0 8 17 9 8 0 16 21 17 16 0
Sample Output
28
给你N*N矩阵,表示N个村庄之间的距离。FJ要把N个村庄全都连接起来,求连接的最短距离。(即传说中的最小生成树)
样例分析:
连接方式:1-----------2-----------3----------4
距离: 4 + 8 + 16 = 24
图论之最小生成树问题。。。下面的是Prime算法复杂度O(n*n)
最小生成树算法思想:
假设N=(V,E) 是连通网,TE是N上最小生成树中边的集合,算法从U={vk},TE={ }开始(即从vk出发求最小生成树,vk∈V)。
重复执行下述操作:
在所有的边(vi,vj)∈E (vi∈U,vj∈V-U)中寻找一条权值最小的边(vi,vj)将其添加到TE中(或打印之),同时把vj添 加到集合U 中 。
反复执行上述操作n-1次(或所有顶点全部加入U时为止)。
通俗的说:1、有一个图N=(V,E),设置一个空集合U,设置路长ans=0。
2、就是先找一个点v1,将v1添加到集合U,再找出和它距离最近的点v2,再把v2添加到集合U,ans加上两点间的距离。
3、再到点集合V-U (属于V,但是不属于U的点)中找出一个离集合U最近的点。将找到的点添加到集合U,ans加上这个最短的距离。
4、如此循环第三步,直到所有的点全到U中。
关于这个动态的PPT,见我传的老师课件:
Accepted | 216K | 16MS | C++ | 1078B |
//AC
#include
#include
int map[105][105];
int lowest[105];
bool vis[105];
int n;
int min()//找到离已经连好了的村庄最短距离的村庄的标号
{
int i;
int m=100000,k=-1;
for(i=1;i<=n;i++)
{
if(!vis[i] && lowest[i]
1258 | Accepted | 288K | 16MS | C++ | 1178B |
#include
#include
#include
using namespace std;
const int maxn = 110;
int n, m;
int ans;
struct Edge{
int u,v;
int w;
}edge[maxn*maxn];
int w[maxn][maxn];
int p[maxn];
bool cmp(Edge a, Edge b)
{
return a.w < b.w;
}
int find(int x)
{
return x == p[x] ? x : p[x] = find(p[x]);
}
void Kruskal()
{
for(int i = 0; i < maxn; i++) p[i] = i;
sort(edge,edge+m,cmp);
for(int i = 0; i < m; i++)
{
int u = find(edge[i].u);
int v = find(edge[i].v);
if(u != v)
{
p[u] = v;
ans += edge[i].w;
}
}
}
int main()
{
while(scanf("%d", &n) != EOF)
{
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
scanf("%d", &w[i][j]);
m = 0; ans = 0;
for(int i = 1; i <= n; i++)
{
for(int j = i+1; j <= n; j++)
{
edge[m].u = i;
edge[m].v = j;
edge[m++].w = w[i][j];
}
}
Kruskal();
printf("%d\n", ans);
}
return 0;
}
1258 | Accepted | 220K | 16MS | C++ | 860B |
#include
#include
#include
using namespace std;
const int maxn = 110;
const int INF = maxn*100000;
int w[maxn][maxn];
int d[maxn];
int vis[maxn];
int n;
int ans;
void Prime()
{
for(int i = 1; i <= n; i++) d[i] = INF;
d[1] = 0;
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++)
{
int x, m = INF;
for(int y = 1; y <= n; y++) if(!vis[y] && d[y] <= m) m = d[x=y];
vis[x] = 1; ans += d[x];
for(int y = 1; y <= n; y++) if(!vis[y])
d[y] = min(d[y], w[x][y]);
}
}
int main()
{
while(scanf("%d", &n) != EOF)
{
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
scanf("%d", &w[i][j]);
ans = 0;
Prime();
printf("%d\n", ans);
}
return 0;
}