HDU-2121-無根(不定根)最小樹形圖模板

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=2121

題目大意:給你N個城市,選擇一個城市建首都,城市編號爲0~N-1,給你M條路,每條路包括u,v,w,即從u到v的花費爲w,現在問你那個城市建首都的話,從這個城市到其餘城市的花費最小,最小花費是多少,如果有多個適合的城市,輸出編號小的城市。無法到達輸出impossible。

解題思路:這是無根最小樹形圖的題,我們可以先假定一個虛根,即源點,並設源點到每個城市的權值爲   全圖所有權值之和大一點,然後就是樹形圖模板,細節在代碼中。

代碼如下:

  1. //本題邊長都爲__int64,其實int型也可以過,但長整型應該更廣,所以本題都爲__int64  
  2. #include <cstdio>  
  3. #include<iostream>  
  4. #include <cstring>  
  5. #include <cstdlib>  
  6. #include<cmath>  
  7. using namespace std;  
  8. typedef double type;  
  9. #define INF 2000000000  
  10. #define N 1005  
  11.   
  12. struct edge //圖的結構體  
  13. {  
  14.     int u,v;__int64 w;  
  15. }e[10005];  
  16.   
  17. int m,n,pre[N],id[N],visit[N],xroot;  
  18. __int64 in[N],sum;  
  19. //eCnt爲圖中的邊數  
  20. //n爲圖中的頂點數  
  21. //pre[i]爲頂點i的前驅節點  
  22. //id[i]爲縮環,形成新圖的中間量  
  23. //in[i]爲點i的最小入邊  
  24. //visit[i]遍歷圖時記錄頂點是否被訪問過  
  25. __int64 directedMST(int root,int nv,int ne)  
  26. {  
  27.     __int64 ans=0;  
  28.     while(1)  
  29.     {  
  30.         //1.找最小入邊  
  31.         for(int i=0;i<nv;i++) in[i]=INF;  
  32.         for(int i=0;i<ne;i++)  
  33.         {  
  34.             int u=e[i].u;  
  35.             int v=e[i].v;  
  36.             if(u!=v&&e[i].w<in[v])  
  37.             {  
  38.                 if(u==root)  //此處標記與源點相連的最小邊  
  39.                     xroot=i;  
  40.                 in[v]=e[i].w;  
  41.                 pre[v]=u;  
  42.             }  
  43.         }  
  44.         for(int i=0;i<nv;i++)                          //判斷圖是否連通  
  45.             if(i!=root&&in[i]==INF) return -1;  //除了跟以外有點沒有入邊,則根無法到達它  
  46.          //2.找環  
  47.         int nodeCnt=0;          //圖中環的數目  
  48.         memset(id, -1, sizeof(id));  
  49.         memset(visit, -1, sizeof(visit));  
  50.         in[root]=0;  
  51.         for(int i=0;i<nv;i++)  
  52.         {  
  53.             ans+=in[i];  
  54.             int v=i;  
  55.             while(visit[v]!=i&&id[v]==-1&&v!=root)//每個點尋找其前序點,要麼最終尋找至根部,要麼找到一個環  
  56.             {  
  57.                 visit[v]=i;  
  58.                 v=pre[v];  
  59.             }  
  60.             if(v!=root&&id[v]==-1)//縮點  
  61.             {  
  62.                 for(int u=pre[v];u!=v;u=pre[u])  
  63.                     id[u]=nodeCnt;  
  64.                 id[v]=nodeCnt++;  
  65.             }  
  66.         }  
  67.         if(nodeCnt==0) break;//如果無環,跳出循環  
  68.         for(int i=0; i<nv; i++)  
  69.             if(id[i]==-1)  
  70.                 id[i]=nodeCnt++;  
  71.         //3.縮點,重新標記  
  72.         for(int i=0;i<ne;i++)  
  73.         {  
  74.             int v=e[i].v;  
  75.             e[i].u=id[e[i].u];  
  76.             e[i].v=id[e[i].v];  
  77.             if(e[i].u!=e[i].v)  
  78.                 e[i].w-=in[v];  
  79.         }  
  80.         nv=nodeCnt;  
  81.         root=id[root];  
  82.     }  
  83.     return ans;  
  84. }  
  85.   
  86. int main()  
  87. {  
  88.     int m;  
  89.     while(scanf(“%d%d”,&n,&m)!=EOF)  
  90.     {  
  91.         sum=0;  
  92.         for(int i=0;i<m;i++)  
  93.         {  
  94.             scanf(”%d%d%I64d”,&e[i].u,&e[i].v,&e[i].w);  
  95.             e[i].u++;e[i].v++;     //都++之後,把0設爲超級源點,聯通各點  
  96.             sum+=e[i].w;  
  97.             if(e[i].u==e[i].v)  
  98.                 e[i].w=INF;//消除自環  
  99.         }  
  100.         sum++;      //此處必須++,因爲需要權值比總權值大,因爲這個w幾次,,,  
  101.         for(int i=m;i<n+m;i++)  
  102.         {  
  103.             e[i].u=0;  
  104.             e[i].v=i-m+1;  
  105.             e[i].w=sum;  
  106.         }  
  107.         __int64 ans=directedMST(0,n+1,m+n);  
  108.         if(ans==-1 || ans-sum>=sum) printf(“impossible\n”);//ans-sum是除去虛根的最小樹形圖的最短路徑,如果這個距離比所有的邊權值和sum還大,說明還有另外的邊由虛點發出,故說明此圖不連通  
  109.         else printf(“%I64d %d\n”, ans-sum, xroot-m);  
  110.         printf(”\n”);  
  111.     }  
  112.     return 0;  
  113. }  
發佈了40 篇原創文章 · 獲贊 35 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章