【HDU - 1301】Jungle Roads(并查集+最小生成树)(内附最小生成树两种算法 克鲁斯特尔算法amp;amp;普里姆算法)
題干:
Jungle Roads
Time Limit: 2000/1000 MS (Java/Others) ? ?Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5505 ? ?Accepted Submission(s): 3976
Problem Description
The Head Elder of the tropical island of Lagrishan has a problem. A burst of foreign aid money was spent on extra roads between villages some years ago. But the jungle overtakes roads relentlessly, so the large road network is too expensive to maintain. The Council of Elders must choose to stop maintaining some roads. The map above on the left shows all the roads in use now and the cost in aacms per month to maintain them. Of course there needs to be some way to get between all the villages on maintained roads, even if the route is not as short as before. The Chief Elder would like to tell the Council of Elders what would be the smallest amount they could spend in aacms per month to maintain roads that would connect all the villages. The villages are labeled A through I in the maps above. The map on the right shows the roads that could be maintained most cheaply, for 216 aacms per month. Your task is to write a program that will solve such problems.?
The input consists of one to 100 data sets, followed by a final line containing only 0. Each data set starts with a line containing only a number n, which is the number of villages, 1 < n < 27, and the villages are labeled with the first n letters of the alphabet, capitalized. Each data set is completed with n-1 lines that start with village labels in alphabetical order. There is no line for the last village. Each line for a village starts with the village label followed by a number, k, of roads from this village to villages with labels later in the alphabet. If k is greater than 0, the line continues with data for each of the k roads. The data for each road is the village label for the other end of the road followed by the monthly maintenance cost in aacms for the road. Maintenance costs will be positive integers less than 100. All data fields in the row are separated by single blanks. The road network will always allow travel between all the villages. The network will never have more than 75 roads. No village will have more than 15 roads going to other villages (before or after in the alphabet). In the sample input below, the first data set goes with the map above.?
?
The output is one integer per line for each data set: the minimum cost in aacms per month to maintain a road system that connect all the villages. Caution: A brute force solution that examines every possible set of roads will not finish within the one minute time limit.?
?
Sample Input
9
A ?2 ?B ?12 ?I ?25
B ?3 ?C ?10 ?H ?40 ?I ?8
C ?2 ?D ?18 ?G ?55
D ?1 ?E ?44
E ?2 ?F ?60 ?G ?38
F ?0
G ?1 ?H ?35
H ?1 ?I ?35
3
A ?2 ?B ?10 ?C ?40
B ?1 ?C ?20
0
?
Sample Output
216
30
解題報告:
? ? ? ? ? ? 最小生成樹再來一發。
ac代碼:
#include<cstdio> #include<algorithm> #include<iostream> using namespace std; struct Node {int u,v;int w;bool operator< ( const Node & b) const{return w<b.w;} } node[105];int f[100],n,cur,cnt,ans; void init() {cnt = 0;cur = 0;ans = 0;for (int i = 0; i <= 27; i++) {f[i] = i; } } int getf(int u) {return u==f[u] ? u : f[u]=getf(f[u]); } void merge(int u,int v) {int t1,t2;t1=getf(u);t2=getf(v);if(t1!=t2) f[t2]=t1; } void input() {char ch[5];int a;for (int i = 1; i <= n - 1; i++) {scanf("%s %d", ch, &a);int u = ch[0] - 'A' + 1;for (int j = 1; j <= a; j++) {int b;scanf(" %s %d", ch, &b);int v = ch[0] - 'A' + 1;node[cnt].u = u;node[cnt].v = v;node[cnt].w = b; cnt++;}} }int main() {while (scanf("%d", &n) ) {getchar();//如果不用getchar 那input中就用%s別用%c if (n==0) break;init();input();sort(node,node+cnt);for(int i = 0; i<cnt; i++) {if(getf(node[i].u) != getf(node[i].v) ) {merge(node[i].u,node[i].v);ans+=node[i].w;cur++;}if(cur==n-1) {break;}}printf("%d\n", ans);}return 0; }貼克魯斯特爾算法ac代碼:(常用!ac代碼1就是用此法)
//hdu-1301-Jungle Roads(克魯斯卡爾) //題目大意:給出個村莊之間的道路及其維修費;從中選取一些路使道路的維修費最小且保證各村莊 //之間道路暢通; //解題思路: //本題最核心的還是構圖,由于輸入的村莊用字母代替這就需要在構圖中將字母替換成數字依次給每個村莊編號; //需要注意的由于輸入的有字符型數據,這就要加一些 getchar()來吸收掉中間的換行空格啥的; //初始化 per[n] 數組一定要注意,把所有村莊都初始化就行啦; //具體如下: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int per[30]; int n,m; struct fun{ //定義結構體數組road[100],用來存放起點、終點和距離 int s;int e;int p; }road[100]; int cmp(fun x,fun y) {return x.p < y.p; } void init() //初始化 per 數組 ;注意初始完 n個村莊即可; {int d;for(d=1;d < = n;d++)per[d]=d; } int find(int x) {int r=x;while(r!=per[r])r=per[r];return r; } bool link(int x,int y) {int fx=find(x),fy=find(y);if(fx!=fy){per[fx]=fy;return true;}return false; } int main() {int j,k,l,sum,i,cnt,a1,a2;char str1,str2;while(scanf("%d",&n)&&(n!=0)){getchar();memset(road,0,sizeof(road));memset(per,0,sizeof(per));init();for(i=1,cnt=1;i < n;i++) //輸入數據,并構圖; {scanf("%c%d",&str1,&m);for(j=1;j<=m;j++){getchar();scanf("%c%d",&str2,&l);road[cnt].s=str1-'A'+1; //將字母編號轉化為數字編號并存入結構體數組中 road[cnt].e=str2-'A'+1;road[cnt].p=l;cnt++;}getchar();} //構圖完成,剩下的就是克魯斯卡爾啦; sort(road,road+cnt,cmp);sum=0;for(j=1;j<=cnt;j++){if(link(road[j].s,road[j].e))sum+=road[j].p;}printf("%d\n",sum);}return 0; }貼Prim算法ac代碼:
//hdu-1301(普里姆算法) //本題用普里姆算法求最小生成樹直接用普里姆的思想構造函數即可; //需要注意的是本題再輸入數據的是時候要先對 map[1000][1000]中的前 n*n //個元素初始化為 一個與 min相同或大于它的數;例如,0xfffffff即可; //(n是結點的個數,由于需要在 n*n 大小的矩陣中構圖,所以初始化 n*n 就行); //為什么要對 map數組初始化呢?一是由于在prim函數中 map要對s[1000]數組賦初值;如果不對map初始化; //那么,s[]數組中沒有數據的就一直為零,與下面的 min比較時,min是永遠大于它們的;這樣得到的min就一直為零 //最終導致sum為零;還有,不對map按上述初始化,在更新時候也無法完成 ; #include<stdio.h> #include<string.h> #define N 0xfffff int map[1000][1000]; int n,m,sum,cnt; void input() {char c1,c2;int i,j,x,y,price;cnt=0;for(i=1;i<=n;i++) //對 map數組初始化為 N ;{for(j=1;j<=n;j++)map[i][j]=N;}for(i=1;i<n;i++) //輸入數據,并構圖; {scanf("%c%d",&c1,&m);x=c1-'A'+1;for(j=1;j<=m;j++){getchar();scanf("%c%d",&c2,&price);y=c2-'A'+1;map[x][y]=map[y][x]=price;}getchar();} } void prim() //普里姆; {int i,j,k,min,v,a,l;int s[1000],vis[1000];memset(vis,0,sizeof(vis));for(i=1;i<=n;i++) s[i]=map[1][i]; //初始化 s 數組; s[1]=0; //本身到本身的距離為零 vis[1]=1; //標記第一個點; sum=0;for(v=1;v<n;v++){min=N;k=1;for(j=1;j<=n;j++)if(!vis[j]&&min>s[j]){min=s[j]; //尋找當前最小權值; k=j;}vis[k]=1; //標記頂點k,表示k已連上樹; sum+=min; //將當前最小權值累加到sum中; for(a=1;a<=n;a++){if(!vis[a]&&s[a]>map[k][a]) //標記當前最小權值的頂點后,更新s[] 數組中的權值 ; s[a]=map[k][a];}}printf("%d\n",sum); } int main() {char c1,c2;int i,j,x,y,price;while(scanf("%d",&n)&&(n!=0)){getchar();input();prim();}return 0; }?
總結:
? ? ? 有的時候用%s讀字符,不是因為別的,就是因為好處理空格,回車這些煩人的東西!!這件事情告訴我們,少用%c多用%s,少用char多用char[ ] !!
?
總結
以上是生活随笔為你收集整理的【HDU - 1301】Jungle Roads(并查集+最小生成树)(内附最小生成树两种算法 克鲁斯特尔算法amp;amp;普里姆算法)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【qduoj - 1121】小明的贪心题
- 下一篇: 【HDU - 1285】确定比赛名次 (