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

NYOJ38 布線問題

編輯:C++入門知識

題目分析:
其實就是求圖的最小生成樹。有兩種方法。prim法和kruskal法。prim法只與節點有關,與邊無關,所以適合於求邊稠密的網的最小生成樹。而kruskal算法與邊有關,故其適合於求邊比較稀疏的網絡。
prim算法:
1)初始化set集為隨意的一個節點,這裡初始化為1。
2)找出與set集中的點相連的,花費最小的並且不再set集中的點,加入set集中。為了計算的方便,先將每個節點相連的所有邊按權值升序排列。
3)直到所有的點都加到set集中,算法就停止了。
kruskal算法:
1)每次找權值最小的邊,如果節點沒有訪問過,就加到set集中。如果訪問過了,就合並兩個set集。
2)這裡為了剪去不必要的迭代,如果連通區域為1,並且所有的點都已經訪問過了,就退出。

參考代碼:

prim算法的代碼:

[cpp]
#include<stdio.h>  
#include<stdlib.h>  
#include<string.h>  
 
struct NODE 

    int to; 
    int w; 
}; 
 
NODE Map[501][501];//Map[i][0].to存放節點i相鄰的點的個數  
bool used[501]; 
int set[501]; 
 
int compare(const void *a, const void *b) 

    NODE *p1 = (NODE *)a; 
    NODE *p2 = (NODE *)b; 
    return p1->w - p2->w; 

 
void GetMap(int n) 

    for(int i = 1; i <= n; ++i) 
        qsort(&Map[i][1], Map[i][0].to, sizeof(Map[i][0]), compare); 

 
int Prim(int n) 

    int num = 1;//set集合內點的個數  
    int i,j; 
    int ans = 0; 
    NODE temp; 
    set[0] = 1; 
    used[1] = true;  
    while(num < n) 
    { 
        temp.to = -1; 
        temp.w = 101; 
        for(i = 0; i < num; ++i) 
        { 
            for(j = 1; j <= Map[set[i]][0].to; ++j) 
            { 
                if(!used[Map[set[i]][j].to]) 
                { 
                    if(Map[set[i]][j].w < temp.w) 
                        temp = Map[set[i]][j]; 
                    break; 
                } 
            }//end for j  
        }//end for i  
        if(temp.to != -1) 
        { 
            ans += temp.w; 
            set[num++] = temp.to; 
            used[temp.to] = true; 
        } 
    }//end for while  
    return ans; 

 
int main() 

    int t,i; 
    int v,e; 
    int a,b,c; 
    int ans; 
    scanf("%d", &t); 
    while(t--) 
    { 
        memset(used,0,sizeof(used)); 
        scanf("%d %d", &v, &e); 
        for(i = 0; i <= v; ++i) 
            Map[i][0].to = 0; 
 
        for(i = 0; i < e; ++i) 
        { 
            scanf("%d %d %d", &a, &b, &c); 
            ++(Map[a][0].to); 
            ++(Map[b][0].to); 
            Map[a][Map[a][0].to].to = b; 
            Map[a][Map[a][0].to].w = c; 
            Map[b][Map[b][0].to].to = a; 
            Map[b][Map[b][0].to].w = c; 
        } 
        scanf("%d", &b); 
        for(i = 1; i < v; ++i) 
        { 
            scanf("%d", &a); 
            b = b < a ? b : a; 
        } 
        GetMap(v); 
        ans = Prim(v); 
        ans += b; 
        printf("%d\n", ans); 
    } 
    return 0; 

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

struct NODE
{
 int to;
 int w;
};

NODE Map[501][501];//Map[i][0].to存放節點i相鄰的點的個數
bool used[501];
int set[501];

int compare(const void *a, const void *b)
{
 NODE *p1 = (NODE *)a;
 NODE *p2 = (NODE *)b;
 return p1->w - p2->w;
}

void GetMap(int n)
{
 for(int i = 1; i <= n; ++i)
  qsort(&Map[i][1], Map[i][0].to, sizeof(Map[i][0]), compare);
}

int Prim(int n)
{
 int num = 1;//set集合內點的個數
 int i,j;
 int ans = 0;
 NODE temp;
 set[0] = 1;
 used[1] = true; 
 while(num < n)
 {
  temp.to = -1;
  temp.w = 101;
  for(i = 0; i < num; ++i)
  {
   for(j = 1; j <= Map[set[i]][0].to; ++j)
   {
    if(!used[Map[set[i]][j].to])
    {
     if(Map[set[i]][j].w < temp.w)
      temp = Map[set[i]][j];
     break;
    }
   }//end for j
  }//end for i
  if(temp.to != -1)
  {
   ans += temp.w;
   set[num++] = temp.to;
   used[temp.to] = true;
  }
 }//end for while
 return ans;
}

int main()
{
 int t,i;
 int v,e;
 int a,b,c;
 int ans;
 scanf("%d", &t);
 while(t--)
 {
  memset(used,0,sizeof(used));
  scanf("%d %d", &v, &e);
  for(i = 0; i <= v; ++i)
   Map[i][0].to = 0;

  for(i = 0; i < e; ++i)
  {
   scanf("%d %d %d", &a, &b, &c);
   ++(Map[a][0].to);
   ++(Map[b][0].to);
   Map[a][Map[a][0].to].to = b;
   Map[a][Map[a][0].to].w = c;
   Map[b][Map[b][0].to].to = a;
   Map[b][Map[b][0].to].w = c;
  }
  scanf("%d", &b);
  for(i = 1; i < v; ++i)
  {
   scanf("%d", &a);
   b = b < a ? b : a;
  }
  GetMap(v);
  ans = Prim(v);
  ans += b;
  printf("%d\n", ans);
 }
 return 0;
}kruskal算法的代碼:

[cpp]
#include<stdio.h>  
#include<stdlib.h>  
#include<string.h>  
 
struct EDGE 

    int from; 
    int to; 
    int w; 
}; 
 
EDGE edge[124760];//所有的邊  
bool used[501]; 
int set[501]; 
 
int compare(const void *a, const void *b) 

    EDGE *p1 = (EDGE *)a; 
    EDGE *p2 = (EDGE *)b; 
    return p1->w - p2->w; 

 
int find(int k) 

    int r = set[k]; 
    while(r != set[r]) 
        r = set[r]; 
    return r; 

 
void Merge(int r1, int r2) 

    if(r1 < r2) 
        set[r2] = r1; 
    else 
        set[r1] = r2; 

 
int Kruskal(int v, int e) 

    int ans = 0; 
    int t, num;//t為連通區域的個數,num為已訪問的節點的個數  
    int r1, r2; 
    t = num = 0; 
    while(num != v && t != 1) 
    { 
        for(int i = 0; i < e; ++i) 
        { 
            if(!used[edge[i].from]) 
            { 
                ++t; 
                ++num; 
                used[edge[i].from] = true; 
            } 
            if(!used[edge[i].to]) 
            { 
                ++t; 
                ++num; 
                used[edge[i].to] = true; 
            } 
 
            r1 = find(edge[i].from); 
            r2 = find(edge[i].to); 
            if(r1 != r2) 
            { 
                --t; 
                Merge(r1, r2); 
                ans += edge[i].w; 
            } 
        }//end for i  
    }//end while  
    return ans; 

 
int main() 

    int t,i; 
    int v,e; 
    int a,b,c; 
    int ans; 
    scanf("%d", &t); 
    while(t--) 
    { 
        memset(used,0,sizeof(used)); 
        scanf("%d %d", &v, &e); 
 
        for(i = 1; i <= v; ++i) 
            set[i] = i; 
 
        for(i = 0; i < e; ++i) 
        { 
            scanf("%d %d %d", &a, &b, &c); 
            edge[i].from = a; 
            edge[i].to = b; 
            edge[i].w = c;       
        } 
        qsort(edge, e, sizeof(edge[0]), compare); 
        scanf("%d", &b); 
        for(i = 1; i < v; ++i) 
        { 
            scanf("%d", &a); 
            b = b < a ? b : a; 
        } 
        ans = Kruskal(v, e); 
        ans += b; 
        printf("%d\n", ans); 
    } 
    return 0; 

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

struct EDGE
{
 int from;
 int to;
 int w;
};

EDGE edge[124760];//所有的邊
bool used[501];
int set[501];

int compare(const void *a, const void *b)
{
 EDGE *p1 = (EDGE *)a;
 EDGE *p2 = (EDGE *)b;
 return p1->w - p2->w;
}

int find(int k)
{
 int r = set[k];
 while(r != set[r])
  r = set[r];
 return r;
}

void Merge(int r1, int r2)
{
 if(r1 < r2)
  set[r2] = r1;
 else
  set[r1] = r2;
}

int Kruskal(int v, int e)
{
 int ans = 0;
 int t, num;//t為連通區域的個數,num為已訪問的節點的個數
 int r1, r2;
 t = num = 0;
 while(num != v && t != 1)
 {
  for(int i = 0; i < e; ++i)
  {
   if(!used[edge[i].from])
   {
    ++t;
    ++num;
    used[edge[i].from] = true;
   }
   if(!used[edge[i].to])
   {
    ++t;
    ++num;
    used[edge[i].to] = true;
   }

   r1 = find(edge[i].from);
   r2 = find(edge[i].to);
   if(r1 != r2)
   {
    --t;
    Merge(r1, r2);
    ans += edge[i].w;
   }
  }//end for i
 }//end while
 return ans;
}

int main()
{
 int t,i;
 int v,e;
 int a,b,c;
 int ans;
 scanf("%d", &t);
 while(t--)
 {
  memset(used,0,sizeof(used));
  scanf("%d %d", &v, &e);

  for(i = 1; i <= v; ++i)
   set[i] = i;

  for(i = 0; i < e; ++i)
  {
   scanf("%d %d %d", &a, &b, &c);
   edge[i].from = a;
   edge[i].to = b;
   edge[i].w = c;  
  }
  qsort(edge, e, sizeof(edge[0]), compare);
  scanf("%d", &b);
  for(i = 1; i < v; ++i)
  {
   scanf("%d", &a);
   b = b < a ? b : a;
  }
  ans = Kruskal(v, e);
  ans += b;
  printf("%d\n", ans);
 }
 return 0;
}
由於prim方法針對節點,而kruskal方法針對邊,所以二者的數據結構有點不一樣。

 

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