程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> zoj - 1406 - Jungle Roads

zoj - 1406 - Jungle Roads

編輯:C++入門知識

題意:有n個村莊,村莊間有一些路,但有一些路可以不要也可連通所有村莊,為節約費用,deal with一些不必要的路,求最少維護總費用。

 

——>>用Kruscal算法生成一棵最小生成樹,輸出即可。

[cpp] 
#include <iostream> 
#include <queue> 
#include <string.h> 
 
using namespace std; 
 
const int maxn = 30;        //1<n<27,開30夠了 
 
struct edge     //定義邊數據類型 

    int v1;     //邊的端點之一 
    int v2;     //邊的端點之一 
    int cost;       //一個月維護這條路的費用 
}; 
 
bool operator < (edge e1, edge e2)      //定義優先隊列排序方式 

    return (e1.cost > e2.cost); 

 
int fa[maxn], height[maxn];     //fa[x]為x的父親,height[i]以i為根的樹的高度(並查集) 
int find(int x)     //找x的根(並查集) 

    while(fa[x] != x) 
    { 
        x = fa[x]; 
    } 
    return x; 

 
bool judge(int x, int y)        //判斷加入邊x——y後是否會開成環,會的返回0,不會的話返回1 

    int new_x = find(x); 
    int new_y = find(y); 
    if(new_x == new_y) return 0;        //會形成環 
    else        //不會形成環 
    { 
        if(height[new_x] > height[new_y]) fa[new_y] = new_x; 
        else if(height[new_x] == height[new_y]) 
        { 
            fa[new_y] = new_x; 
            height[new_x]++; 
        } 
        else fa[new_x] = new_y; 
        return 1; 
    } 

 
bool G[maxn][maxn];     //用鄰接矩陣來存儲圖 
bool vis[maxn], viss[maxn];         //vis、viss均用來判斷該村莊是否走過 
int n;      //n個村莊 
 
void dfs(int i)     //深度優先遍歷修改一個連通塊 

    vis[i] = 1; 
    int j; 
    for(j = 1; j <= n; j++) 
        if(G[i][j] == 1 && vis[j] == 0) 
            dfs(j); 
    return; 

 
 
bool is_ok()        //判斷村莊是否已連通 

    memset(viss, 0, sizeof(viss)); 
    int count = 0, ok = 1, i; 
    for(i = 1; i <= n; i++) 
    { 
        if(viss[i] == 0) 
        { 
            dfs(i); 
            count++; 
            if(count >= 2) 
            { 
                ok = 0; 
                break; 
            } 
        } 
    } 
    if(ok) return 1; 
    else return 0; 

 
int main() 

    int i, j; 
    while(cin>>n) 
    { 
        if(n == 0) return 0; 
        char c1, c2; 
        int num1, num2; 
        for(i = 1; i <= n; i++) 
        { 
            fa[i] = i; 
            height[i] = 1; 
        } 
 
        priority_queue<edge> qu;        //用優先隊列取最小費用的路徑 
 
        edge newnode; 
        memset(G, 0, sizeof(G)); 
        for(i = 1; i <= n-1; i++) 
        { 
            cin>>c1>>num1; 
            for(j = 1; j <= num1; j++) 
            { 
                cin>>c2>>num2; 
                G[(int)(c1-'A')+1][(int)(c2-'A')+1] = 1;        //把A,B,C...變成1,2,3... 
                G[(int)(c2-'A')+1][(int)(c1-'A')+1] = 1; 
                newnode.v1 = (int)(c1-'A')+1; 
                newnode.v2 = (int)(c2-'A')+1; 
                newnode.cost = num2; 
                qu.push(newnode);       //入列 
            } 
        } 
 
        int sum = 0;        //費用總數 
        int OK = 0;     //整個island是否連通的標志 
        memset(vis, 0, sizeof(vis)); 
        while(!OK && !qu.empty()) 
        { 
            if(judge(qu.top().v1, qu.top().v2))     //用並查集實現判斷加入那條邊是否會形成環,不會的時候 
            { 
                OK = 0; 
                vis[qu.top().v1] = 1;       //將這兩個村莊標記為已走 
                vis[qu.top().v2] = 1; 
                sum += qu.top().cost;       //累加總費用 
                if(is_ok()) OK = 1;     //加入此邊後判斷所有村莊是否已連通 
            } 
            qu.pop(); 
        } 
        cout<<sum<<endl; 
    } 
    return 0; 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved