分類:圖論,生成樹,最短路,并查集
作者:ACShiryu
時間:2011-7-28
地址:ACShiryu's Blog
Heavy Transportation
Time Limit:?3000MS | Memory Limit:?30000K | |
Total Submissions:?11929 | Accepted:?3171 |
Description
Background?
Hugo Heavy is happy. After the breakdown of the Cargolifter project he can now expand business. But he needs a clever man who tells him whether there really is a way from the place his customer has build his giant steel crane to the place where it is needed on which all streets can carry the weight.?
Fortunately he already has a plan of the city with all streets and bridges and all the allowed weights.Unfortunately he has no idea how to find the the maximum weight capacity in order to tell his customer how heavy the crane may become. But you surely know.?
Problem?
You are given the plan of the city, described by the streets (with weight limits) between the crossings, which are numbered from 1 to n. Your task is to find the maximum weight that can be transported from crossing 1 (Hugo's place) to crossing n (the customer's place). You may assume that there is at least one path. All streets can be travelled in both directions.
Hugo Heavy is happy. After the breakdown of the Cargolifter project he can now expand business. But he needs a clever man who tells him whether there really is a way from the place his customer has build his giant steel crane to the place where it is needed on which all streets can carry the weight.?
Fortunately he already has a plan of the city with all streets and bridges and all the allowed weights.Unfortunately he has no idea how to find the the maximum weight capacity in order to tell his customer how heavy the crane may become. But you surely know.?
Problem?
You are given the plan of the city, described by the streets (with weight limits) between the crossings, which are numbered from 1 to n. Your task is to find the maximum weight that can be transported from crossing 1 (Hugo's place) to crossing n (the customer's place). You may assume that there is at least one path. All streets can be travelled in both directions.
Input
The first line contains the number of scenarios (city plans). For each city the number n of street crossings (1 <= n <= 1000) and number m of streets are given on the first line. The following m lines contain triples of integers specifying start and end crossing of the street and the maximum allowed weight, which is positive and not larger than 1000000. There will be at most one street between each pair of crossings.
Output
The output for every scenario begins with a line containing "Scenario #i:", where i is the number of the scenario starting at 1. Then print a single line containing the maximum allowed weight that Hugo can transport to the customer. Terminate the output for the scenario with a blank line.
Sample Input
1 3 3 1 2 3 1 3 4 2 3 5
Sample Output
Scenario #1: 4
題目大意是就是何處一個圖,n個頂點和m條邊,每個邊都有最大承載量,現在我要從1點運送貨物到n點,求能運送貨物的最大重量。
對于數據,第一行為t代表測試數據個數,第二行為n和m(意義見上),接著m行,每行三個整數分別是代表一條邊的起點,終點及最大承重量。輸出能運送貨物的最大重量,格式見樣例。注意數據輸完后還要再多輸一個空行。
對于數據,從1運到3有兩種方案
方案1:1-2-3,其中1-2承重為3,2-3承重為5,則可以運送貨物的最大重量是3(當大于3時明顯1到不了2)
方案2:1-3,可知1-3承重為4,故此路可運送貨物的最大重量是4,故答案輸出4
因為此前也沒做過圖論題,對一些算法都不熟,再剛開始題意理解有問題,WA了幾次,看懂題意后,搜了下別人的解題報告,說是Dijkstra的變形或這求最大生成樹。也許對Dijkstra運用(壓根就沒用過)的不是很熟,一直不知道怎么下手,連樣列都過不了。后就直接轉到求最大生成樹上去了,網上大部分代碼是Prim算法,由于《算法入門競賽經典》書沒介紹該算法,暫時還沒看,所以就選擇Kruskal求最大生成樹。然后選擇Kruskal的一個問題就是連通分量的處理,《入門經典》是用的并查集來處理,因為對生成樹算法不是很熟,就直接套的上面的模板。然后題目就是編程了求最大生成樹,并找出從1-n的最小權值的邊。當然,這棵樹不用搜完,因為,你從1到n不一定會每一個節點都走過,當將1-n連通時此時的權值就是所求的值;轉換用Kruskal時因為數組開大了MLE一次,開小了RE一次,最后決定還是動態分配靠譜些。不過因為一個小細節又WA了一次,最后改正,終于AC了,你說,AC一題我容易不!!!總之ACM搞圖論的上輩子都是折翼的天使!!!
如果有時間,這題還會再做一遍的,用Prim算法和Dijkstra試一下!
參考代碼:
1 //第一次提交的代碼基本是套模板的,和自己寫的出入較大,不習慣,將代碼修改下感覺也許更好!,第一次提交的代碼見最下面
2 #include<iostream>
3 #include<cstdlib>
4 #include<cstdio>
5 #include<cstring>
6 #include<algorithm>
7 #include<cmath>
8 using namespace std;
9 const int inf = (1<<20);
10 int p[1005]; //p是用于并查集的,r是用來存儲邊序號的
11 struct prog {
12 int w,v,u; //記錄起點,終點,權值
13 };
14 bool cmp(prog a,prog b)
15 {//間接排序函數,
16 return a.w>b.w;
17 }
18 int find(int x)
19 {//并查集里的find函數,你懂的
20 return p[x]==x?x:p[x]=find(p[x]);
21 }
22 int main()
23 {
24 int t;
25 cin >> t;
26 int k = 1;
27 while(t--)
28 {
29 int n ,m;
30 cin >> n >> m;
31 prog *r;
32 r=new prog[m];
33 int i ;
34 for ( i = 0 ; i < m ; i ++ )
35 cin>>r[i].u>>r[i].v>>r[i].w; //輸入邊的信息
36
37 for ( i =1 ; i <= n; i ++ )
38 p[i]=i;//初始化并查集
39
40 sort(r,r+m,cmp);//根據邊的權值的大小將邊的序號進行排序,r[i]表示第i+1大的邊存儲在u,v,w數組中的序號
41 int ans=inf; //將答案初始化為最大值
42 for ( i = 0 ; i < m ; i ++ )
43 {
44 int x=find(r[i].u);
45 int y=find(r[i].v);
46 if(x!=y)
47 {//如果該邊所在的兩邊不在同一個連通分量里,則連接該邊
48 if(ans>r[i].w)//如果該邊的權值比ans小(實際上一定不會比ans大),則更新ans
49 ans=r[i].w;
50 p[x]=y;//連接該邊
51 if(find(1)==find(n))//當1和n連通時,則說明找到了一條從1到n的路,并且可知該路的所有邊的權值都是最大的,故邊的最小權值就是答案
52 break;
53 }
54 }
55 //輸出答案,格式如題所述
56 cout<<"Scenario #"<<k<<":"<<endl;
57 cout<<ans<<endl<<endl;
58 k++;
59 }
60 return 0;
61 }
附:第一次參考代碼
1 #include<iostream>
2 #include<cstdlib>
3 #include<cstdio>
4 #include<cstring>
5 #include<algorithm>
6 #include<cmath>
7 using namespace std;
8 const int inf = (1<<20);
9 int *p,*r; //p是用于并查集的,r是用來存儲邊序號的
10 int *u,*v,*w; //分別代表邊的起點,終點,和權值,明顯不是我的風格,先熟悉下模板,不得不這樣寫
11 bool cmp(const int a,const int b)
12 {//間接排序函數,
13 return w[a]>w[b];
14 }
15 int find(int x)
16 {//并查集里的find函數,你懂的
17 return p[x]==x?x:p[x]=find(p[x]);
18 }
19 int main()
20 {
21 int t;
22 cin >> t;
23 int k = 1;
24 while(t--)
25 {
26 int n ,m;
27 cin >> n >> m;
28 int i ;
29 u=new int[m];
30 v=new int[m];
31 w=new int[m];
32 r=new int[m];//動態分配
33 for ( i = 0 ; i < m ; i ++ )
34 {
35 int a , b , c ;
36 cin>>a>>b>>c;
37 u[i]=a;
38 v[i]=b;
39 w[i]=c;//加入邊
40 }
41 p=new int[n+1];
42 for ( i =1 ; i <= n; i ++ )
43 p[i]=i;//初始化并查集
44 for ( i = 0 ;i < m ; i ++ )
45 r[i]=i;//初始化邊序號
46 sort(r,r+m,cmp);//根據邊的權值的大小將邊的序號進行排序,r[i]表示第i+1大的邊存儲在u,v,w數組中的序號
47 int ans=inf; //將答案初始化為最大值
48 for ( i = 0 ; i < m ; i ++ )
49 {
50 int e=r[i];//找到第i+1大的邊
51 int x=find(u[e]);
52 int y=find(v[e]);
53 if(x!=y)
54 {//如果該邊所在的兩邊不在同一個連通分量里,則連接該邊
55 if(ans>w[e])//如果該邊的權值比ans小(實際上一定不會比ans大),則更新ans
56 ans=w[e];
57 p[x]=y;//連接該邊
58 if(find(1)==find(n))//當1和n連通時,則說明找到了一條從1到n的路,并且可知該路的所有邊的權值都是最大的,故邊的最小權值就是答案
59 break;
60 }
61 }
62 //輸出答案,格式如題所述
63 cout<<"Scenario #"<<k<<":"<<endl;
64 cout<<ans<<endl<<endl;
65 k++;
66 }
67 return 0;
68 }