「LOJ#10068」「一本通 3.1 練習 3」秘密的牛奶運輸(次小生成樹
阿新 • • 發佈:2018-10-23
source log ems ado john line flex iostream 編號
題目描述
Farmer John 要把他的牛奶運輸到各個銷售點。運輸過程中,可以先把牛奶運輸到一些銷售點,再由這些銷售點分別運輸到其他銷售點。 運輸的總距離越小,運輸的成本也就越低。低成本的運輸是 Farmer John 所希望的。不過,他並不想讓他的競爭對手知道他具體的運輸方案,所以他希望采用費用第二小的運輸方案而不是最小的。現在請你幫忙找到該運輸方案。
輸入格式
第一行是兩個整數 N,M,表示頂點數和邊數;
接下來 M 行每行 3 個整數,x,y,z,表示一條路的兩端 x,y 和距離 z。
輸出格式
僅一行,輸出第二小方案。
樣例
樣例輸入
4 4
1 2 100
2 4 200
2 3 250
3 4 100
樣例輸出
450
數據範圍與提示
對於全部數據,1≤N≤500,1≤M≤10?4??,1≤z≤10?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,M,表示頂點數和邊數;
接下來 M 行每行 3 個整數,x,y,z,表示一條路的兩端 x,y 和距離 z。
輸出格式
僅一行,輸出第二小方案。
樣例
樣例輸入
4 4
1 2 100
2 4 200
2 3 250
3 4 100
樣例輸出
450
數據範圍與提示
對於全部數據,1≤N≤500,1≤M≤10?4??,1≤z≤10?9??,數據可能有重邊。
「LOJ#10068」「一本通 3.1 練習 3」秘密的牛奶運輸(次小生成樹