1003 電話連線

自為風月馬前卒發表於2017-04-13
題目描述 Description

一個國家有n個城市。若干個城市之間有電話線連線,現在要增加m條電話線(電話線當然是雙向的了),使得任意兩個城市之間都直接或間接經過其他城市有電話線連線,你的程式應該能夠找出最小費用及其一種連線方案。

輸入描述 Input Description

    輸入檔案的第一行是n的值(n<=100).

    第二行至第n+1行是一個n*n的矩陣,第i行第j列的數如果為0表示城市i與城市j有電話線連線,否則為這兩個城市之間的連線費用(範圍不超過10000)。

輸出描述 Output Description

       輸出檔案的第一行為你連線的電話線總數m,第二行至第m+1行為你連線的每條電話線,格式為i j,(i<j), i j是電話線連線的兩個城市。輸出請按照Prim演算法發現每一條邊的順序輸出,起始點為1.

       第m+2行是連線這些電話線的總費用。

樣例輸入 Sample Input

5

0 15 27 6 0

15 0 33 19 11

27 33 0 0 17

6 19 0 0 9

0 11 17 9 0

樣例輸出 Sample Output

2

1 4

2 5

17

資料範圍及提示 Data Size & Hint

n<=100

分類標籤 Tags

 

裸prim但是我上來就智障的敲了個kruskal也是醉了

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 struct node
  7 {
  8     int u;
  9     int v;
 10     int w;
 11 }edge[10001];
 12 struct ans
 13 {
 14     int x;
 15     int y;
 16 }a[10001];
 17 int num=1;
 18 int f[1001];
 19 int cmp(const node &a,const node &b)
 20 {
 21     return a.w<b.w;
 22 }
 23 int find(int x)
 24 {
 25     if(x!=f[x])
 26     f[x]=find(f[x]);
 27     return f[x];
 28 }
 29 void unionn(int x,int y)
 30 {
 31     int fx=find(x);
 32     int fy=find(y);
 33     f[fx]=fy;
 34 }
 35 int comp(const ans &a,const ans &b)
 36 {
 37     if(a.y>b.y)return 1;
 38     if(a.y==b.y&&a.x<b.x)return 1;
 39     return 0;
 40 }
 41 int now=1;
 42 int main()
 43 {
 44     int n;
 45     scanf("%d",&n);
 46     for(int i=1;i<=n;i++)f[i]=i;
 47     for(int i=1;i<=n;i++)
 48     {
 49         for(int j=1;j<=n;j++)
 50         {
 51             int p;
 52             scanf("%d",&p);
 53             if(j>i)
 54             {
 55                 edge[num].u=i;
 56                 edge[num].v=j;
 57                 edge[num].w=p;
 58                 num++;
 59             }
 60         }
 61     }
 62     sort(edge+1,edge+num,cmp);
 63     int k=0;
 64     int tot=0;
 65     int feiyong=0;
 66     for(int i=1;i<=num;i++)
 67     {
 68         if(find(edge[i].u)!=find(edge[i].v))
 69         {
 70             unionn(edge[i].u,edge[i].v);
 71             //printf("%d %d\n",edge[i].u,edge[i].v);
 72             if(edge[i].w!=0)
 73             {
 74                 tot++;
 75                 feiyong=feiyong+edge[i].w;
 76                 //ans1[now]=edge[i].u;
 77                 //ans2[now]=edge[i].v;
 78                 a[now].x=min(edge[i].u,edge[i].v);
 79                 a[now].y=max(edge[i].u,edge[i].v);
 80                 k++;
 81                 now++;
 82             }
 83             
 84         }
 85         if(k==n-1)break;
 86     }
 87     /*for(int i=1;i<=now;i++)
 88     {
 89         for(int j=i;j<=now;j++)
 90         {
 91             if(ans1[j]>ans1[j+1])
 92             {
 93                 swap(ans1[j],ans1[j+1]);
 94                 swap(ans1[j],ans2[j+1]);
 95             }
 96         }
 97     }*/
 98     sort(a+1,a+now,comp);
 99     printf("%d\n",tot);
100     for(int i=1;i<=now-1;i++)
101     {
102         printf("%d %d\n",a[i].x,a[i].y);
103     }
104     printf("%d",feiyong);
105     return 0;
106 }
 1 #include <iostream>
 2 #include <algorithm>
 3 using namespace std;
 4 const int MAXN = 105;
 5 const int INF = 2147483647;
 6 int i, j, n;
 7 long long ans = 0;
 8 int edge[MAXN][MAXN], key[MAXN], p[MAXN], vis[MAXN] = {0}, //edge表示存的邊 key表示權值,p表示父親,vis表示是否已經存在已生成的樹中
 9         f[MAXN], l[MAXN], m = 0; //f表示頭,右邊表示尾
10 int main() {
11     cin >> n;
12     for(i = 1; i <= n; i++)for(j = 1; j <= n; j++) cin >> edge[i][j];
13     for(i = 1; i <= n; i++) key[i] = INF;
14     key[1] = 0; //
15     p[1] = 1;
16     int Mini, Min;
17     for(i = 0; i < n; i++) { //之需要加最多n條邊,故迴圈n次
18         Min = INF;
19         for(j = 1; j <= n; j++) if(!vis[j] && key[j] < Min) {
20                 Mini = j;    //找key值最小的點,即與樹相鄰的節點的最小權值邊
21                 Min = key[j];
22             }
23         vis[Mini] = 1; //設定訪問過,即生成樹已連線Mini這個節點
24         ans += key[Mini];
25         if(key[Mini]) {
26             f[m] =   min(p[Mini], Mini); //字典序的邊
27             l[m++] = max(p[Mini], Mini); //同上
28         }
29         for(j = 1; j <= n; j++) //偽鬆弛,更新樹臨邊節點的key值並維護p域
30             if(!vis[j] && edge[Mini][j] < key[j]) {
31                 key[j] = edge[Mini][j];
32                 p[j] = Mini;
33             }
34     }
35     cout << m << endl;
36     for(i = 0; i < m; i++) cout << f[i] << ' ' << l[i] << endl;
37     cout << ans;
38     return 0;
39 }

 

相關文章