題解報告:hdu 1233 還是暢通工程
阿新 • • 發佈:2018-05-18
str recommend 題解報告 出現 最小 dijkstra sum 正整數 output Problem Description
某省調查鄉村交通狀況,得到的統計表中列出了任意兩村莊間的距離。省政府“暢通工程”的目標是使全省任何兩個村莊間都可以實現公路交通(但不一定有直接的公路相連,只要能間接通過公路可達即可),並要求鋪設的公路總長度為最小。請計算最小的公路總長度。
Input
測試輸入包含若幹測試用例。每個測試用例的第1行給出村莊數目N ( < 100 );隨後的N(N-1)/2行對應村莊間的距離,每行給出一對正整數,分別是兩個村莊的編號,以及此兩村莊間的距離。為簡單起見,村莊從1到N編號。
當N為0時,輸入結束,該用例不被處理。 Output 對每個測試用例,在1行裏輸出最小的公路總長度。 Sample Input 3 1 2 1 1 3 2 2 3 4 4 1 2 1 1 3 4 1 4 1 2 3 3 2 4 2 3 4 5 0 Sample Output 3 5
Huge input, scanf is recommended. 解題思路:①Prim算法的核心就是加點法,每次把離目標集合最小權值的一點加入其中。其算法跟Dijkstra大同小異,不同的是mincost數組記錄的是當前點到目標集合的最小權值,下次就取最小權值的端點加入就可以了。其算法時間復雜度是O(n2 ),適合稠密圖。
②Kruskal算法的核心就是加邊法,並且運用到並查集。先將各邊權值按升序排列,然後貪心加邊,加邊時查看當前邊的兩端點是否為同一個連通圖中的兩點,如果是的話,就不能納入目標集合,因為會出現回路,即產生圈,這樣就不滿足樹的定義了,否則將其加入。其時間復雜度是O(elogn),適合稀疏圖。
AC代碼之Prim算法:
當N為0時,輸入結束,該用例不被處理。 Output 對每個測試用例,在1行裏輸出最小的公路總長度。 Sample Input 3 1 2 1 1 3 2 2 3 4 4 1 2 1 1 3 4 1 4 1 2 3 3 2 4 2 3 4 5 0 Sample Output 3 5
Huge input, scanf is recommended. 解題思路:①Prim算法的核心就是加點法,每次把離目標集合最小權值的一點加入其中。其算法跟Dijkstra大同小異,不同的是mincost數組記錄的是當前點到目標集合的最小權值,下次就取最小權值的端點加入就可以了。其算法時間復雜度是O(n2
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int INF = 0x3f3f3f3f; 4 const int maxn = 105; 5 int n,a,b,c,mincost[maxn],cost[maxn][maxn];6 bool vis[maxn]; 7 int Prim(){//加點法 8 for(int i=1;i<=n;++i)//這裏選取節點1作為起點,mincost為各節點到最小生成樹節點集合的最小權值 9 mincost[i]=cost[1][i]; 10 mincost[1]=0;vis[1]=true;//標記已訪問 11 int res=0;//計算最小生成樹的權值 12 for(int i=1;i<n;++i){ 13 int k=-1;//標記為-1 14 for(int j=1;j<=n;++j)//找出到最小生成樹節點集合的權值最小的還沒入集合的一點15 if(!vis[j] && (k==-1 || mincost[k]>mincost[j]))k=j; 16 if(k==-1)break;//如果還是-1,表示已經完成最小生成樹的建立 17 vis[k]=true;//將節點k納入最小生成樹節點的集合 18 res+=mincost[k];//加上其權值 19 for(int j=1;j<=n;++j)//更新k的鄰接點到最小生成樹節點集合的最小權值 20 if(!vis[j])mincost[j]=min(mincost[j],cost[k][j]);//還沒歸納的節點 21 } 22 return res; 23 } 24 int main() 25 { 26 while(~scanf("%d",&n) && n){ 27 memset(vis,false,sizeof(vis)); 28 for(int i=1;i<=n;++i){ 29 for(int j=1;j<=n;++j) 30 cost[i][j]=(i==j?0:INF); 31 } 32 for(int i=1;i<=n*(n-1)/2;++i){ 33 cin>>a>>b>>c; 34 cost[a][b]=cost[b][a]=c; 35 } 36 printf("%d\n",Prim()); 37 } 38 return 0; 39 }
AC代碼之Kruskal算法:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,father[105],sum; 4 struct edge{int u,v,cost;}es[5000]; 5 bool cmp(const edge& e1,const edge& e2){ 6 return e1.cost<e2.cost; 7 } 8 void init_union_find(){//將每個節點當作根節點 9 for(int i=1;i<=n;++i)father[i]=i; 10 } 11 int find_father(int x){//遞歸查找根節點 12 if(father[x]==x)return x; 13 else return father[x]=find_father(father[x]); 14 } 15 void unite(int x,int y,int z){ 16 x=find_father(x); 17 y=find_father(y); 18 if(x!=y){//如果邊的兩端點的根節點不相同,即分別為非連通圖,則可以歸並 19 sum+=z;//加上最小權值 20 father[x]=y;//將x的父節點改成y 21 } 22 } 23 int main() 24 { 25 while(~scanf("%d",&n) && n){ 26 for(int i=1;i<=n*(n-1)/2;++i) 27 scanf("%d %d %d",&es[i].u,&es[i].v,&es[i].cost); 28 sort(es+1,es+n*(n-1)/2+1,cmp);//權值按從小到大排序 29 sum=0;init_union_find();//初始化 30 for(int i=1;i<=n*(n-1)/2;++i) 31 unite(es[i].u,es[i].v,es[i].cost); 32 printf("%d\n",sum); 33 } 34 return 0; 35 }
題解報告:hdu 1233 還是暢通工程