1. 程式人生 > >「LOJ#10068」「一本通 3.1 練習 3」秘密的牛奶運輸(次小生成樹

「LOJ#10068」「一本通 3.1 練習 3」秘密的牛奶運輸(次小生成樹

source log ems ado john line flex iostream 編號

題目描述

Farmer John 要把他的牛奶運輸到各個銷售點。運輸過程中,可以先把牛奶運輸到一些銷售點,再由這些銷售點分別運輸到其他銷售點。 運輸的總距離越小,運輸的成本也就越低。低成本的運輸是 Farmer John 所希望的。不過,他並不想讓他的競爭對手知道他具體的運輸方案,所以他希望采用費用第二小的運輸方案而不是最小的。現在請你幫忙找到該運輸方案。

輸入格式

第一行是兩個整數 N,MN,MN,M,表示頂點數和邊數;

接下來 MMM 行每行 333 個整數,x,y,zx,y,zx,y,z,表示一條路的兩端 x,yx,yx,y 和距離 zz

z

輸出格式

僅一行,輸出第二小方案。

樣例

樣例輸入

4 4
1 2 100
2 4 200
2 3 250
3 4 100

樣例輸出

450

數據範圍與提示

對於全部數據,1≤N≤500,1≤M≤104,1≤z≤1091\le N\le 500,1\le M\le 10^4,1\le z\le 10^91N500,1M10?4??,1z10?9??,數據可能有重邊。

題解

這是一道裸的次小生成樹。

次小生成樹的兩種食用方法:

  • 就叫它法一吧。
    • 首先求個最小生成樹。
    • 然後每次刪掉一條樹邊,求樹邊兩端兩點的最短路。
    • 時間復雜度$O(nmlogm)$
  • 就叫它法二吧。
    • 也是首先求個最小生成樹。
    • 之後求樹上每兩點的路徑間最大的邊權,需要$O(n^2)$。(枚舉每個點做根,然後$O(n)$遍歷
    • 然後枚舉每個非樹邊,設端點為$i,j$。
    • 那麽如果把這條邊接上生成樹,那麽就把它所在的環上邊權最大的那條邊斷掉,就是接上這條邊的最優解。
    • 所以枚舉每條邊,維護$最小生成樹的權值和-MAX[i][j]+a[i][j]$的最小值。
    • 復雜度$O(n^2+m)$

然後這裏寫的是法二。

 1 編號    題目    狀態    分數    總時間    內存    代碼 / 答案文件    提交者    提交時間
 2 #240021    #10068. 「一本通 3.1 練習 3」秘密的牛奶運輸 Accepted    100    74 ms    1404 KiB    C++ / 1.3 K    qwerta    2018-10-22 20:33:11
 3 #include<algorithm>
 4 #include<iostream>
 5 #include<cstdio>
 6 using namespace std;
 7 struct emm{
 8     int l,r,v,tag;
 9 }a[10003];
10 bool cmp(emm qaq,emm qwq){
11     return qaq.v<qwq.v;
12 }
13 int fa[503];
14 int fifa(int x)
15 {
16     if(fa[x]==x)return x;
17     return fa[x]=fifa(fa[x]);
18 }
19 struct ahh{
20     int e,f,v;
21 }b[1003];
22 int h[503];
23 int cnt=0;
24 void con(int x,int y,int len)//加邊
25 {
26     b[++cnt].f=h[x];
27     h[x]=cnt;
28     b[cnt].e=y;
29     b[cnt].v=len;
30     b[++cnt].f=h[y];
31     h[y]=cnt;
32     b[cnt].e=x;
33     b[cnt].v=len;
34     return;
35 }
36 int MAX[503][503];//兩點樹上路徑中邊權最大值
37 int s;
38 void dfs(int x)//dfs找MAX[s][x]
39 {
40     for(int i=h[x];i;i=b[i].f)
41     if(!MAX[s][b[i].e]&&b[i].e!=s)
42     {
43         MAX[s][b[i].e]=max(MAX[s][x],b[i].v);
44         dfs(b[i].e);
45     }
46     return;
47 }
48 int main()
49 {
50     //freopen("a.in","r",stdin);
51     int n,m;
52     scanf("%d%d",&n,&m);
53     for(int i=1;i<=m;++i)
54     {
55         int x,y,z;
56         scanf("%d%d%d",&x,&y,&z);
57         a[i]=(emm){x,y,z};//建原圖
58     }
59         //跑最小生成樹
60     for(int i=1;i<=n;++i)
61       fa[i]=i;
62     sort(a+1,a+m+1,cmp);
63     int k=n-1,i=0;
64     long long now=0;//記錄最小生成樹的邊權和
65     while(k)
66     {
67         ++i;
68         int u=fifa(a[i].l),v=fifa(a[i].r);
69         if(u!=v)
70         {
71             fa[u]=v;
72             con(a[i].l,a[i].r,a[i].v);//建樹圖
73             k--;
74             now+=a[i].v;
75             a[i].tag=1;//標記為樹邊
76         }
77     }
78     for(s=1;s<=n;++s)
79     {
80         dfs(s);
81     }
82     long long ans=1e15;
83     for(int i=1;i<=m;++i)
84     if(!a[i].tag&&a[i].v>MAX[a[i].l][a[i].r])//如果該邊為非樹邊並且它的權值大於左右端點的樹上距離(因為是次小生成樹,所以權值要比最小生成樹大
85     {
86         ans=min(ans,now-MAX[a[i].l][a[i].r]+a[i].v);//把路徑上最大的換成這條邊的答案
87     }
88     cout<<ans;
89     return 0;
90 }

題目描述

Farmer John 要把他的牛奶運輸到各個銷售點。運輸過程中,可以先把牛奶運輸到一些銷售點,再由這些銷售點分別運輸到其他銷售點。 運輸的總距離越小,運輸的成本也就越低。低成本的運輸是 Farmer John 所希望的。不過,他並不想讓他的競爭對手知道他具體的運輸方案,所以他希望采用費用第二小的運輸方案而不是最小的。現在請你幫忙找到該運輸方案。

輸入格式

第一行是兩個整數 N,MN,MN,M,表示頂點數和邊數;

接下來 MMM 行每行 333 個整數,x,y,zx,y,zx,y,z,表示一條路的兩端 x,yx,yx,y 和距離 zzz

輸出格式

僅一行,輸出第二小方案。

樣例

樣例輸入

4 4
1 2 100
2 4 200
2 3 250
3 4 100

樣例輸出

450

數據範圍與提示

對於全部數據,1≤N≤500,1≤M≤104,1≤z≤1091\le N\le 500,1\le M\le 10^4,1\le z\le 10^91N500,1M10?4??,1z10?9??,數據可能有重邊。

「LOJ#10068」「一本通 3.1 練習 3」秘密的牛奶運輸(次小生成樹