安慰奶牛

問題描述

Farmer John變得很是懶,他不想再繼續維護供奶牛之間供通行的道路。道路被用來鏈接N個牧場,牧場被連續地編號爲1到N。每個牧場都是一個奶牛的家。FJ計劃除去P條道路中儘量多的道路,可是還要保持牧場之間 的連通性。你首先要決定那些道路是須要保留的N-1條道路。第j條雙向道路鏈接了牧場Sj和Ej(1 <= Sj <= N; 1 <= Ej <= N; Sj != Ej),並且走完它須要Lj的時間。沒有兩個牧場是被一條以上的道路所鏈接。奶牛們很是傷心,由於她們的交通系統被削減了。你須要到每個奶牛的住處去安慰她們。每次你到達第i個牧場的時候(即便你已經到過),你必須花去Ci的時間和奶牛交談。你每一個晚上都會在同一個牧場(這是供你選擇的)過夜,直到奶牛們都從悲傷中緩過神來。在早上 起來和晚上回去睡覺的時候,你都須要和在你睡覺的牧場的奶牛交談一次。這樣你才能完成你的 交談任務。假設Farmer John採納了你的建議,請計算出使全部奶牛都被安慰的最少時間。ios

輸入格式

第1行包含兩個整數N和P。算法

接下來N行,每行包含一個整數Ci。數組

接下來P行,每行包含三個整數Sj, Ej和Lj。ide

輸出格式
輸出一個整數, 所須要的總時間(包含和在你所在的牧場的奶牛的兩次談話時間)。
樣例輸入
5 7
10
10
20
6
30
1 2 5
2 3 5
2 4 12
3 4 17
2 5 15
3 5 6
樣例輸出
176
數據規模與約定

5 <= N <= 10000,N-1 <= P <= 100000,0 <= Lj <= 1000,1 <= Ci <= 1,000。學習

 

這個就是那個生成樹的題目。我就是用的 剛纔那篇文章的方法求解的生成樹。無奈,很是悲劇的是我用鄰接表存儲無向圖遠遠的超出了內存限制。所以只能作出前三個題目。。。
由於個人數組開的很小,題目要求10000,我只開了100.
這個題目理解起來還挺奇怪的什麼睡覺不睡覺的,反正我是沒有看懂。不過這題也說明了一個點權能夠轉化爲邊權來計算。首先他說要去掉一些沒有必要的路,這樣的話很天然的就想到了最小生成樹啦。而後我就學習了用鄰接表存無向圖的最小生成樹方法。還有題目中說安慰牛要花費時間,走路上要花費時間,因此選擇一條道路花費的時間是一條路的時間的兩倍再加上兩個點的時間。而後要在起點睡一覺,因此起點的牛要多安慰一遍,爲了使結果最小,就選安慰時間最少的點做爲起點。而後就有了下面的代碼。
 1 #include<iostream>
 2 using namespace std;
 3 const int in = 1000;
 4 int main()
 5 {
 6     int N,P;
 7     int c[101];
 8     int l[101][101] = {0};
 9     cin >>N>>P;
10     int i;
11     for(i = 0;i < N;i++)
12     {
13         cin >> c[i];
14     }
15     int j,k;
16     for(k = 0;k < P;k++)
17     {
18         int c;
19         cin >>i>>j;
20         cin>>c;
21         l[i - 1][j - 1] = l[j - 1][i - 1] = c;
22     }
23     int map[101][101];
24     for(i = 0;i < N;i++)
25     {
26         for(j = 0;j < N;j++)
27         {
28             if(l[i][j] == 0)map[i][j] = in;
29             else map[i][j] = 2*l[i][j]+c[i]+c[j];
30         }
31     }
32     int cost[101];
33     int point[101];
34     bool visit[101];
35     for(i = 0;i < N;i++)
36     {
37         cost[i] = map[0][i];
38         point[i] = 0;
39         visit[i] = false;
40     }
41     visit[0] = true;
42     for(k = 1;k<N;k++)
43     {
44         int min = in;
45         j = 0;
46         for(i = 0;i < N;i++)
47         {
48             if(!visit[i] && min > cost[i]){min = cost[i];j = i;}
49         }
50         visit[j] = true;
51         for(i = 0;i < N;i++)
52         {
53             if(!visit[i] && cost[i] > map[j][i]){cost[i] = map[j][i];point[i] = j;}
54         }
55     }
56     int min = c[0]; 
57     for(i = 0;i < N;i++)
58     {
59         if(min > c[i])min = c[i];
60     }
61     int sum = 0;
62     for(i = 1;i < N;i++)
63     {
64         sum += map[i][point[i]];
65     }
66     cout<<sum+min<<endl;
67     return 0;
68 }

 

這樣顯然是不行的,由於二階矩陣實在是太大了。因此就用鏈表存儲該圖。可是用鏈表存儲的最小生成樹算法我並不會寫。先粘一個經過的代碼。
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int MAXN=10000+10;
 6 const int MAXM=100000+10;
 7 const int INF=100000;
 8 int cost[MAXN],fa[MAXN];
 9 int find(int cur)
10 {
11   return cur==fa[cur]? cur:fa[cur]=find(fa[cur]);
12 }
13 struct edge
14 {
15   int from,to,val;
16   bool operator <(const edge& x)const{
17     return val<x.val;
18   }
19 }e[MAXM];
20 
21 int main()
22 {
23   int mini=INF,index;
24   int n,p;
25   scanf("%d%d",&n,&p);
26   for(int i=1;i<=n;i++)
27   {
28     scanf("%d",&cost[i]);
29     mini=min(cost[i],mini);
30     fa[i]=i;
31   }
32   for(int i=0;i<p;i++)
33   {
34     scanf("%d%d%d",&e[i].from,&e[i].to,&e[i].val);
35     e[i].val=(e[i].val<<1)+cost[ e[i].from ] + cost [ e[i].to ];
36   }
37   sort(e,e+p);
38   int ans=0;
39   for(int i=0;i<p;i++)
40   {
41     int x=e[i].from,y=e[i].to;
42     int root_x=find(x),root_y=find(y);
43     if(root_x==root_y)   continue;
44     fa[root_x]=root_y;
45     ans+=e[i].val;
46   }
47   printf("%d\n",ans+mini);
48   return 0;
49 }
View Code

等我再研究一下用鏈表的怎麼寫。spa

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息