菜鸟就要老老实实重新学起:
Prim
遍历所有点,找到最近的点加入树中,更新距离数组dist [ ] 。邻接矩阵存图。
模版:
#define N 1010
bool vis[N];
int g[N][N],dist[N];
int prim(int n)
{
int minn,i,j,pos=1,res=0;
memset(vis,false,sizeof(vis));
//第一次给dist数组赋值
for(i=1; i<=n; i++)
dist[i]=g[pos][i];
dist[pos]=0;vis[pos]=true;
for(i=1; i<n; i++)
{
//找出最小权值并记录位置
minn=INF;
for(j=1; j<=n; j++)
if(!vis[j]&&dist[j]<minn)
{
minn=dist[j];
pos=j;
}
res+=minn;
vis[pos]=true;
//更新权值,与dijkstra不同的地方(起点为所有加入生成树的节点,找到树最近的点)
for(j=1; j<=n; j++)
if(!vis[j]&&dist[j]>g[pos][j])
dist[j]=g[pos][j];
}
return res;
}
Kruskal
邻接表存图,升序排列所有边,并查集维护点集合,遍历边合并点集,得到最小生成树。
模版:
#define N 101000
#define M 1000100
int f[N];
struct node
{
int u,v;
int r;
//升序排列
friend bool operator < (node a, node b)
{
return a.r < b.r;
}
}edge[M];
void inserts(int u,int v,int w)
{
edge[cnt].u = u;
edge[cnt].v = v;
edge[cnt++].r = w;
edge[cnt].u = v;
edge[cnt].v = u;
edge[cnt++].r = w;
}
void Init(int n)
{
for(int i=1;i<=n;i++)
f[i] = i;
}
//并查集维护点集合
int getf(int u)
{
if(f[u] != u)
f[u] = getf(f[u]);
return f[u];
}
bool unions(int x,int y)
{
x=getf(x);
y=getf(y);
if(x!=y)
{
f[x] = y;
return false;
}
return true;
}
int kruskal(int n,int m)
{
sort(edge,edge+m);
int i,k,res;
i=k=res=0;
//找n-1条边
while(k<n-1)
{
//已遍历所有边
if(i == m)break;
//并查集判断不形成环,则该边加入生成树中
if(!unions(edge[i].u,edge[i].v))
{
k++;
res+=edge[i].r;
}
i++;
}
return res;
}
eg:
POJ1861 Network
http://poj.org/problem?id=1861
题意:
模版题,求最小生成树,输出最大边,边数,所有边。
思路:
要输出边所以用kruskal,模版题,测试用。
code:
#define N 1123
int n,m;
int flag,sum,ave,ans,res,cnt;
int a[N],b[N];
int f[N];
struct node
{
int x,y;
int r,w;
friend bool operator < (node a, node b)
{
return a.r < b.r;
}
};
node edge[M];
void inserts(int u,int v,int w)
{
edge[cnt].x = u;
edge[cnt].y = v;
edge[cnt++].r = w;
}
void init()
{
for(int i=1;i<=n;i++)
f[i] = i;
}
int getf(int u)
{
if(f[u] != u)
f[u] = getf(f[u]);
return f[u];
}
bool unions(int u,int v)
{
u = getf(u);
v = getf(v);
if(u != v)
{
f[u] = v;
return false;
}
return true;
}
int kruskal()
{
sort(edge,edge+m);
int i,j,k,res;
i=k=res=0;
ans=-INF;
while(k<n-1)
{
if(i == m)
break;
if(!unions(edge[i].x,edge[i].y))
{
a[k] = i;
ans = max(ans,edge[i].r);
k++;
res+=edge[i].r;
}
i++;
}
printf("%d\n",edge[i-1].r);
printf("%d\n",i);
for(j=0;j<i;j++)
printf("%d %d\n",edge[j].x,edge[j].y);
return res;
}
int main()
{
int i,j,k,kk,t,x,y;
while(scanf("%d%d",&n,&m)!=EOF&&n)
{
init();
for(i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&t);
inserts(x,y,t);
}
t = kruskal();
}
return 0;
}
POJ1258 Agri-Net
http://poj.org/problem?id=1258
题意:
模版题,求最小生成树,输出总距离。
思路:
prim模版,测试。
code:
#define N 123
int n,m;
int flag,sum,ave,ans,res;
int g[N][N];
bool vis[N];
int dist[N];
void inserts()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&g[i][j]);
}
int prim()
{
int minn,i,j,pos=1,res=0;
memset(vis,false,sizeof(vis));
for(i=1;i<=n;i++)
dist[i] = g[pos][i];
dist[pos] = 0;
vis[pos] = true;
for(i=1;i<n;i++)
{
minn = INF;
for(j=1;j<=n;j++)
if(!vis[j] && dist[j]<minn)
{
minn = dist[j];
pos = j;
}
res+=minn;
vis[pos] = true;
for(j=1;j<=n;j++)
if(!vis[j] && dist[j]>g[pos][j])
dist[j] = g[pos][j];
}
return res;
}
int main()
{
int i,j,k,kk,t,x,y;
while(scanf("%d",&n)!=EOF&&n)
{
inserts();
printf("%d\n",prim());
}
return 0;
}