1. 程式人生 > >最小生成樹:新的開始

最小生成樹:新的開始

mem sel nbsp i++ 這一 time 生成 space 可能

題目描述

發展采礦業當然首先得有礦井,小 FF 花了上次探險獲得的千分之一的財富請人在島上挖了 nnn 口礦井,但他似乎忘記考慮的礦井供電問題……

為了保證電力的供應,小 FF 想到了兩種辦法:

  1. 在這一口礦井上建立一個發電站,費用為 vvv(發電站的輸出功率可以供給任意多個礦井)。
  2. 將這口礦井與另外的已經有電力供應的礦井之間建立電網,費用為 ppp。

小 FF 希望身為「NewBe_One」計劃首席工程師的你幫他想出一個保證所有礦井電力供應的最小花費。

輸入格式

第一行一個整數 nnn,表示礦井總數。

2~n+12\sim n+12n+1 行,每行一個整數,第 iii 個數 viv_iv?i?? 表示在第 iii 口礦井上建立發電站的費用。

接下來為一個 n×nn\times nn×n 的矩陣 ppp,其中 pi,jp_{i,j}p?i,j?? 表示在第 iii 口礦井和第 jjj 口礦井之間建立電網的費用(數據保證有pi,j=pj,ip_{i,j}=p_{j,i}p?i,j??=p?j,i??,且 pi,i=0p_{i,i}=0p?i,i??=0)。

輸出格式

輸出僅一個整數,表示讓所有礦井獲得充足電能的最小花費。

樣例

樣例輸入

4  
5  
4 
4  
3  
0 2 2 2  
2 0 3 3  
2 3 0 4  
2 3 4 0

樣例輸出

9

樣例解釋

小 FF 可以選擇在 444 號礦井建立發電站然後把所有礦井都不其建立電網,總花費是 3+2+2+2=93+2+2+2=93+2+2+2=9。

分析:這道題原來用的克魯斯卡爾算法(最小生成樹+最小v[i]),在LOJ上最多得了50分。其實它可能出現一個礦井修電網還不如修電站的情況,故改用Prim算法

#include<bits/stdc++.h>
using namespace std;
int a[1000][1000],v[1000];
int dis[10000];
bool book[10000];
#define inf 1e12;
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>v[i];
        a[i][n
+1]=v[i]; a[n+1][i]=v[i]; } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>a[i][j]; memset(book,0,sizeof book); for(int k=1;k<=n+1;k++) { dis[k]=a[1][k]; } book[1]=1; int ans=0; for(int k=1;k<=n;k++) { long long mins=inf; int minj; for(int j=1;j<=n+1;j++) { if(!book[j]&&dis[j]<mins) { mins=dis[j]; minj=j; } } book[minj]=1; ans+=dis[minj]; for(int j=1;j<=n+1;j++) if(book[j]==0&&dis[j]>a[minj][j]) dis[j]=a[minj][j]; } cout<<ans; }

最小生成樹:新的開始