poj1061Jungle Roads

poj1061Jungle Roads

题意:就是求最小生成树所有边之和。是到最小生成树的水题,就是存图委实有点恶心。

1.Kruskal Algorithm
把所有边从小到大排序,在加入边的过程中,1.判断是否所有点已经进入树中,如果是,则停止。2.判断对应的点是否已经加入集合,如果是则不加入该点。最后计算边之和。

# include <stdio.h>
# include <string.h>
# include <stdlib.h>

const int maxn = 26;
int n;
int cnt;
struct st   {
    char a;
    char b;
    int c;
}edge[maxn*maxn];

int f[maxn];

int cmp(const void *a,const void *b)    {
    struct st *c = (st*)a;
    struct st *d = (st*)b;
    return c->c-d->c;
}
int find(int x) {
    while(x != f[x])    {
        x = f[x];
    }

    return x;
}

bool Union(int x,int y) {
    int a = find(x);
    int b = find(y);
    if(a != b)  {
        f[b] = a;
        return true;
    }
    else
        return false;

}

int main()  {
    int str[5];
    int str1[5];
    int a,b;
    while(scanf("%d",&n) != EOF && n)   {
        getchar();
        cnt = 0;
        for(int i = 0; i < 26; i++) {
            f[i] = i;
        }
        int count = 0, sum = 0;
        for(int i = 1; i <= n-1; i++)   {
            scanf("%s%d",str,&a);
            for(int i = 0; i < a; i++)  {
                scanf("%s%d",str1,&b);
                edge[cnt].a = str[0] - 'A';
                edge[cnt].b = str1[0] - 'A';
                edge[cnt].c = b;
                cnt++;
            }
        }
        qsort(edge,cnt,sizeof(edge[0]),cmp);
        for(int i = 0; i < cnt; i++)    {
            if(count == n-1) break;
            if(Union(edge[i].a,edge[i].b))  {
                count++;
                sum += edge[i].c;
            }
        }
        printf("%d\n",sum);
    }
    return 0;
}

维护三个数组。
dis:当前该点到集合需要的最小长度
parent:dis边对应的集合中的点,把集合该点记录下来,以记录最小生成树的边
vis:该点是否已在集合中。
松弛的思想来遍历即可

# include <stdio.h>
# include <string.h>
# include <queue>
using namespace std;

const int INF = 0x3f3f3f3f;

int n;
int Map[30][30];
char str[5];
char str1[5];
int dis[30];
int parent[30];
bool vis[30];
int sum;

void spfa() {
    memset(vis,0,sizeof(vis));
    memset(dis,INF,sizeof(dis));
    memset(parent,-1,sizeof(parent));
    vis[1] = true;
    dis[1] = 0;
    queue<int> Q;
    Q.push(1);
    while(!Q.empty())    {
        int v = Q.front();
        Q.pop();
        for(int i = 2; i <= n; i++) {
            if(!vis[i] && dis[i] > Map[i][v])   {
                dis[i] = Map[i][v];
                parent[i] = v;
            }
        }
        int m = 0x3f3f3f3f, x = 0;
        for(int i = 2; i <= n; i++) {
            if(!vis[i] && m > dis[i])   {
                m = dis[i];
                x = i;
            }
        }
        if(x == 0)  break;
        vis[x] = true;
        Q.push(x);
    }
}
int main()  {
    while(scanf("%d",&n) != EOF && n)   {
        memset(Map,INF,sizeof(Map));
        for(int i = 1; i <= n-1; i++)   {
            int num;
            scanf("%s%d",str,&num);
            for(int i = 0; i < num; i++)  {
                int w;
                scanf("%s%d",str1,&w);
                int a, b, c;
                a = str[0] - 'A'+1;
                b = str1[0] - 'A'+1;
                c = w;
                Map[a][b] = Map[b][a] = c;
            }
        }
        sum = 0;
        spfa();
        for(int i = 2; i <= n; i++) {
            int from = parent[i];
            if(from != -1)
                sum += Map[from][i];
        }
        printf("%d\n",sum);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值