菜鸟系列——最小生成树

菜鸟就要老老实实重新学起:
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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值