HDU 1301 Jungle Roads (Kruskal求最小生成树)

题意:有n个点,要在他们之间搭建公路,知道一些点之间搭建公路的代价,求使所以点可以相互到达的最小代价(无向图、无环)。


思路一:Kruskal算法,先将建造路的代价由小到大排序,尽量取最小代价的点(如果取某条路后形成了环,没有增加连接的点,浪费,应舍弃)。


#include 
   
   
    
    
#include 
    
    
     
     
int loop[30];  //用于确定点的集合
struct Line
{
    int dist, a, b;
}line[100];

int comp(const void *a, const void *b)
{
    return (*(Line *)a).dist - (*(Line *)b).dist;
}

int find(int i)  //确定某点所在的集合(的代表元)
{
    if(loop[i] == i) return i;
    return find(loop[i]);
}

int main()
{
    #ifdef LOCAL
    freopen("data.in", "r", stdin);
    #endif

    int  n, k, num, ans, road, dist;
    char l, r;
    int i, j, x, y;
    while(scanf("%d", &n) != EOF && n)
    {
        num = 0; ans = 0; road = 0;
        for(i = 0; i < n - 1; i++)
        {

            scanf(" %c%d", &l, &k);
            for(j = 0; j < k; j++)
            {
                scanf(" %c%d", &r, &dist);
                line[num].dist = dist;
                line[num].a = l - 'A';
                line[num].b = r - 'A';
                num++;
            }
            loop[i] = i;  //起始时各点在一个只含自己的集合中
        }
        loop[i] = i;
        qsort(line, num, sizeof(line[0]), comp);
        for(i = 0; i < num; i++)
        {
            //printf("%d%c%c\n",line[i].dist, line[i].a+'A', line[i].b+'B');
            //确定两个点分别属于的集合(的代表元)
            x = find(loop[line[i].a]);
            y = find(loop[line[i].b]);
            if(x != y)  //所属集合不同,在两点间增加路不会形成环
            {
                ans += line[i].dist;
                loop[y] = x;  //将两点相连,之后合并同两点所属集合
                road++;
                if(road == n - 1) break;
            }
        }
        printf("%d\n", ans);
    }

    return 0;
}

    
    
   
   

思路二:Prim算法。


#include 
   
   
    
    
#include 
    
    
     
     
int dist[30][30], vis[30], mincost[30];
int n, ans;
int min(int a, int b)
{
    if(a < b || b == 0)return a;
    else return b;
}

int prim()
{
	for(int u = 0; u < n; u++)//初始化最短路径
	{
		mincost[u] = 100000;
		vis[u] = 0;
	}
	mincost[0] = 0;
	int ans = 0;
	while(1)
	{
		int v = -1;
		for(int u = 0; u < n; u++)
		{
			if(!vis[u] && (v == -1 || mincost[u] < mincost[v]))
			//在未连接的点中找路径最短的点(v=-1时未找到未连接的点)
				v = u;
		}
		if(v == -1) break;  //找不到未连接的点,即完成最小生成树
		vis[v] = 1;  //标记新加入的点
		ans += mincost[v];  //统计连接点v后的最小路径长度
		//printf("v=%d, mincost=%d\n", v, mincost[v]);
		for(int u = 0; u < n; u++)  //在连接了v点的条件下更新最短路径
		{
            mincost[u] = min(mincost[u], dist[v][u]);
		}
	}
	return ans;
}

int main()
{
    #ifdef LOCAL
    freopen("data.in", "r", stdin);
    #endif

    char a, c;
    int b, d;
    while(scanf("%d", &n) != EOF && n)
    {
        memset(dist, 0, sizeof(dist));
        memset(vis, 0, sizeof(vis));
        for(int i = 0; i < n - 1; i++)
        {
            scanf(" %c%d", &a, &b);
            for(int j = 0; j < b ;j++)
            {
                scanf(" %c%d", &c, &d);
                dist[a - 'A'][c - 'A'] = dist[c - 'A'][a - 'A'] = d;
            }
        }
        /*for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < n; j++)
                printf("%2d ", dist[i][j]);
            printf("\n");
        }
        */
        printf("%d\n", prim());
    }

    return 0;
}

    
    
   
   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值