畅通工程之局部最小花费问题 (并查集)

来源:互联网 发布:财务报表数据下载 编辑:程序博客网 时间:2024/06/05 02:09

7-1 畅通工程之局部最小花费问题(35 分)

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

输入格式:

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

输出格式:

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

输入样例:

41 2 1 11 3 4 01 4 1 12 3 3 02 4 2 13 4 5 0

输出样例:

3

#include <iostream>


using namespace std;

//思路:先把原有的路合并为一个集合(不含回路),然后利用cruscal思想,把权值由小到大的路合并到集合里(不含回路),直到集合内点数等于总点数

//判断有没有回路只需判断两个点的祖先是不是相同,相同则不符
//坑题,数据上限是5000,所以数组要大
int father[10001];
int num[10001];
int num1=0;
typedef struct
{
    int start;
    int stop;
    int fee;
    int flag;
}road;
typedef struct
{
    int note;
    int no;
}hehe;
hehe hehe1[10001];
int tofind(int x)//找根
{
    int temp=x;
    while(father[temp]!=-1)
    {
        temp=father[temp];
    }
    return temp;
}
void tounion(int a,int b)//把b的根连到a的根上,合并成一个
{
    int x=tofind(b);
    father[tofind(b)]=tofind(a);
    num[tofind(a)]+=num[x];
    num1=num[tofind(a)];


}
road r[10001];
int main()
{


    int n;
    cin>>n;
    if(n==1)
    {
        cout<<0;
        return 0;
    }
    int i;
    for(i=1;i<=n;i++)
    {
        father[i]=-1;
        num[i]=1;
    }//初始化,把每一个数的爸爸初始化为-1


    for(i=0;i<(n*(n-1))/2;i++)
    {
        cin>>r[i].start>>r[i].stop>>r[i].fee>>r[i].flag;
        if(r[i].flag==1)
        {
            if(tofind(r[i].start)==tofind(r[i].stop))
                ;
            else
            {
                tounion(r[i].start,r[i].stop);
                if(num1==n)
                {
                    cout<<0;
                    return 0;
                }
            }


        }
    }

    int tt=0;
    int j;
    for(i=0;i<n*(n-1)/2;i++)
    {
        if(r[i].flag==0)
        {
            hehe1[tt].no=r[i].fee;
            hehe1[tt].note=i;
            tt++;
        }
    }
    for (i=1; i<tt; i++)
        for(j=0; j<tt-i; j++)
        {
           if(hehe1[j].no>hehe1[j+1].no)
           {
               int t1,t2;
               t1=hehe1[j].no;
               hehe1[j].no=hehe1[j+1].no;
               hehe1[j+1].no=t1;
               t2=hehe1[j].note;
               hehe1[j].note=hehe1[j+1].note;
               hehe1[j+1].note=t2;
           }
        }//把权值由小到大排序
        int sum=0;
    for(i=0;i<tt;i++)
    {
        int temp=hehe1[i].note;
        if(tofind(r[temp].start)==tofind(r[temp].stop))
                continue;
        else
        {
            sum+=hehe1[i].no;
            tounion(r[temp].start,r[temp].stop);
            if(num1==n)
            {
                cout<<sum;
                break;
            }
        }


    }
}

阅读全文
0 0
原创粉丝点击