1. 程式人生 > >城市建設(兩次kruscal演算法)

城市建設(兩次kruscal演算法)

棟棟居住在一個繁華的C市中,然而,這個城市的道路大都年久失修。市長準備重新修一些路以方便市民,於是找到了棟棟,希望棟棟能幫助他。 

C市中有n個比較重要的地點,市長希望這些地點重點被考慮。現在可以修一些道路來連線其中的一些地點,每條道路可以連線其中的兩個地點。另外由於C市有一條河從中穿過,也可以在其中的一些地點建設碼頭,所有建了碼頭的地點可以通過河道連線。 

棟棟拿到了允許建設的道路的資訊,包括每條可以建設的道路的花費,以及哪些地點可以建設碼頭和建設碼頭的花費。 

市長希望棟棟給出一個方案,使得任意兩個地點能只通過新修的路或者河道互達,同時花費盡量小。 

樣例說明 
建設第2、3、4條道路,在地點4、5建設碼頭,總的花費為9。 
資料規模和約定 
對於100%的資料,1  < =  n  < =  10000,1  < =  m  < =  100000,-1000< =c< =1000,-1< =w_i< =1000,w_i≠0。 
 

輸入

輸入的第一行包含兩個整數n,  m,分別表示C市中重要地點的個數和可以建設的道路條數。所有地點從1到n依次編號。 
接下來m行,每行三個整數a,  b,  c,表示可以建設一條從地點a到地點b的道路,花費為c。若c為正,表示建設是花錢的,如果c為負,則表示建設了道路後還可以賺錢(比如建設收費道路)。 
接下來一行,包含n個整數w_1,  w_2,  …,  w_n。如果w_i為正數,則表示在地點i建設碼頭的花費,如果w_i為-1,則表示地點i無法建設碼頭。 
輸入保證至少存在一個方法使得任意兩個地點能只通過新修的路或者河道互達。 

輸出

輸出一行,包含一個整數,表示使得所有地點通過新修道路或者碼頭連線的最小花費。如果滿足條件的情況下還能賺錢,那麼你應該輸出一個負數。 

樣例輸入

5  5 
1  2  4 
1  3  -1 
2  3  3 
2  4  5 
4  5  10 
-1  10  10  1  1 

輸出:

9

#include <bits/stdc++.h>
using namespace std;
const int AX = 2e5+6;
int w[AX];

int pre[10006];

struct Node
{
    int x, y, w;
} e[AX];

bool cmp( const Node &a, const Node &b )
{
    return a.w < b.w;
}

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

void mix( int x, int y )
{
    int xx = find(x);
    int yy = find(y);
    if( xx != yy )
    {
        pre[yy] = xx;
    }
}

int Kruscal( int m )
{

    int ans = 0;
    sort( e, e + m, cmp );
    for( int i = 0 ; i < m ; i++ )
    {
        if( find(e[i].x) != find(e[i].y) || e[i].w < 0 )
        {
            mix(e[i].x,e[i].y);
            ans += e[i].w;
        }
    }
    return ans ;
}

int main()
{
    int n,m;
    cin >> n >> m;
    int x;
    for( int i = 0 ; i < m ; i ++ )
    {
        cin >> e[i].x >> e[i].y >> e[i].w;
    }
    int k = m;
    for( int i = 1 ; i <= n ; i++ )
    {
        cin >> x;
        if( x != -1 )
        {
            e[k].x = 0;//k為邊數;
            e[k].y = i;
            e[k++].w = x;//表示0號到i號所需花費;此條邊的權值為x;
        }
    }

    for( int i = 0 ; i <= n ; i++ )
        pre[i] = i;
    int res1 = Kruscal(m);

    int fa = find(1);
    bool flag = true;
    for( int i = 2 ; i <= n ; i++ )
    {
        if( find(i) != fa )
        {
            flag = false;
            break;
        }
    }

    for( int i = 0 ; i <= n ; i++ )
        pre[i] = i;
    int res2 = Kruscal(k);

    if( flag == false )
    {
        cout << res2 << endl;
    }
    else
    {
        int res = min( res1, res2 );
        cout << res << endl;
    }
    return 0 ;
}

評測環境:WindowsXP,FreePascal2.40,Pentium(R) Dual-Core CPU [email protected],2G記憶體