PTA 7-14 畅通工程之局部最小花费问题

某地区经过对城镇交通状况的调查,得到现有城镇间快速道路的统计数据,并提出“畅通工程”的目标:使整个地区任何两个城镇间都可以实现快速交通(但不一定有直接的快速道路相连,只要互相间接通过快速路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建快速路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全地区畅通需要的最低成本。

输入格式:

输入的第一行给出村庄数目N (1≤N≤100);随后的N(N−1)/2行对应村庄间道路的成本及修建状态:每行给出4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态 — 1表示已建,0表示未建。

输出格式:

输出全省畅通需要的最低成本。

输入样例:

4
1 2 1 1
1 3 4 0
1 4 1 1
2 3 3 0
2 4 2 1
3 4 5 0

输出样例:

3

代码实现:

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

#define INFINITY 99999999
#define MaxVertexNum 1010
typedef int Vertex;
typedef int WeightType;

typedef struct GNode *PtrToGNode;
struct GNode{
    int Nv;
    int Ne;
    WeightType G[MaxVertexNum][MaxVertexNum];
};
typedef PtrToGNode MGraph;
struct Evode{
    int Head;
    int Tail;
    int lowcost;
    int if_built;
}Edge[MaxVertexNum*(MaxVertexNum-1)/2+1];

MGraph ReadG(int N)
{
    MGraph G=(MGraph)malloc(sizeof(struct GNode));
    G->Nv=N;
    G->Ne=N*(N-1)/2;
    int i,j;
    for(i=1;i<=G->Nv;i++)
    {
        for(j=1;j<=G->Nv;j++)
        {
            G->G[i][j]=INFINITY;
            if(i==j)
            {
                G->G[i][j]=0;
            }
        }
    }
    for(i=1;i<=G->Ne;i++)
    {
        int a,b,x,y;
        scanf("%d%d%d%d",&a,&b,&x,&y);
        Edge[i].Head=a;
        Edge[i].Tail=b;
        Edge[i].lowcost=x;
        Edge[i].if_built=y;
        G->G[a][b]=x;
        G->G[b][a]=x;
        if(y==1)
        {
            Edge[i].lowcost=0;
        }
    }
    return G;
}

void Sort(MGraph G){
    int m =G->Ne;
    int i;
    for(i=1;i<=G->Ne;i++)
    {
        int min=i;
        for(int j=i+1;j<=G->Ne;j++)
        {
            if(Edge[j].lowcost<Edge[min].lowcost)
                min=j;
        }
        struct Evode t=Edge[i];
        Edge[i]=Edge[min];
        Edge[min]=t;
    }
}

int find(int x,int *set)
{
    if(set[x]<0)
        return x;
    else
        return set[x]=find(set[x],set);
}

int lunion(int x,int y,int *set)
{
    int px=find(x,set);
    int py=find(y,set);
    if(px!=py)
    {
        if(set[px]<=set[py])
        {
            set[px]+=set[py];
            set[py]=px;
        }
        else
        {
            set[py]+=set[px];
            set[px]=py;
        }
        return 1;
    }
    return 0;
}

int count_set(MGraph G,int* set)
{
    int i;
    int count=0;
    for(i=1;i<=G->Nv;i++)
    {
        if(set[i]<0)
            count++;
    }
    return count;
}

int MiniSpanTree_Kruskal(MGraph G,int *set)
{
    int m=1;
    int cost=0;
    while(m<=G->Ne&&count_set(G,set)!=1)
    {
        struct Evode t=Edge[m++];
        int a,b;
        a=t.Head;b=t.Tail;
        if(!t.if_built)
        {
            int f=lunion(a,b,set);
            if(f)cost+=t.lowcost;
        }
        else
        {
            int f=lunion(a,b,set);
            if(f)cost+=t.lowcost;
        }
    }
    return cost;
}

int main()
{
    int N;
    scanf("%d",&N);
    MGraph G=ReadG(N);
    Sort(G);
    int set[MaxVertexNum];
    int i;
    for(i=1;i<=G->Nv;i++)
    {
        set[i]=-1;
    }
    int cost=MiniSpanTree_Kruskal(G,set);
    printf("%d\n",cost);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值