1. 程式人生 > >7-50 暢通工程之區域性最小花費問題(35 分)

7-50 暢通工程之區域性最小花費問題(35 分)

題目大意:略。

解題思路:Kruskal 演算法+首先要將已經修建的道路進行並查集合併操作,用 set 存集合中結點的個數來判斷是否所有點都已經操作完成,剩餘的點按照基本操作進行就好了。

AC 程式碼

#include<bits/stdc++.h>
#include<cmath>

#define mem(a,b) memset(a,b,sizeof a);
#define INF 0x3f3f3f3f

using namespace std;

typedef long long ll;

const int maxn=110;

struct edge
{
    int u,v,w,f;
}es[maxn*maxn];

int n,m;
int pre[maxn];
set<int> st; // 判斷是否所有點都已經操作完成

void init()
{
    st.clear();
    m=n*(n-1)/2;
    for(int i=1;i<=n;i++) pre[i]=i;
}

int cmp(edge e1,edge e2)
{
    if(e1.f==e2.f) return e1.w<e2.w;
    return e1.f>e2.f;
}

int find(int x)
{
    return pre[x]==x ? x : pre[x]=find(pre[x]);
}

int kruskal()
{
    int ans=0,fu,fv;
    for(int i=0;i<m;i++)
    {
        fu=find(es[i].u), fv=find(es[i].v);
        st.insert(es[i].u); st.insert(es[i].v);
        if(es[i].f==1)
        {
            pre[fu]=fv;
        }
        else if(fu!=fv)
        {
            ans+=es[i].w;
            pre[fu]=fv;
        }

        if(st.size()==n) break;
    }

    printf("%d\n",ans);
}

int main()
{
    while(~scanf("%d",&n))
    {
        init();
        for(int i=0;i<m;i++)
            scanf("%d%d%d%d",&es[i].u,&es[i].v,&es[i].w,&es[i].f);
        sort(es,es+m,cmp); // 因為 Kruskal 演算法是按照邊從小到大選擇
        kruskal();
    }

    return 0;
}