日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

问题 1437: [蓝桥杯][历届试题]城市建设(最小生成树)

發布時間:2023/12/15 编程问答 72 豆豆
生活随笔 收集整理的這篇文章主要介紹了 问题 1437: [蓝桥杯][历届试题]城市建设(最小生成树) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目描述
棟棟居住在一個繁華的C市中,然而,這個城市的道路大都年久失修。市長準備重新修一些路以方便市民,于是找到了棟棟,希望棟棟能幫助他。

C市中有n個比較重要的地點,市長希望這些地點重點被考慮。現在可以修一些道路來連接其中的一些地點,每條道路可以連接其中的兩個地點。另外由于C市有一條河從中穿過,也可以在其中的一些地點建設碼頭,所有建了碼頭的地點可以通過河道連接。

棟棟拿到了允許建設的道路的信息,包括每條可以建設的道路的花費,以及哪些地點可以建設碼頭和建設碼頭的花費。

市長希望棟棟給出一個方案,使得任意兩個地點能只通過新修的路或者河道互達,同時花費盡量小。

樣例說明
建設第2、3、4條道路,在地點4、5建設碼頭,總的花費為9。
數據規模和約定
對于100%的數據,1 < = n < = 10000,1 < = m < = 100000,-1000< =c< =1000,-1< =w_i< =1000,w_i≠0。

輸入
輸入的第一行包含兩個整數n, m,分別表示C市中重要地點的個數和可以建設的道路條數。所有地點從1到n依次編號。
接下來m行,每行三個整數a, b, c,表示可以建設一條從地點a到地點b的道路,花費為c。若c為正,表示建設是花錢的,如果c為負,則表示建設了道路后還可以賺錢(比如建設收費道路)。
接下來一行,包含n個整數w_1, w_2, …, w_n。如果w_i為正數,則表示在地點i建設碼頭的花費,如果w_i為-1,則表示地點i無法建設碼頭。
輸入保證至少存在一個方法使得任意兩個地點能只通過新修的路或者河道互達。
輸出
輸出一行,包含一個整數,表示使得所有地點通過新修道路或者碼頭連接的最小花費。如果滿足條件的情況下還能賺錢,那么你應該輸出一個負數。
樣例輸入
5 5
1 2 4
1 3 -1
2 3 3
2 4 5
4 5 10
-1 10 10 1 1
樣例輸出
9
思路:如果都不能建立碼頭的話,我們直接調用最小生成樹算法就可以了。但是如果有碼頭的話,我們就要分情況討論了。
①不用建碼頭就是連通圖。沒有說明一定是連通圖,因此我們要分情況討論。這種情況下,我們要看建立碼頭和不建立碼頭哪種情況花費最小。
②本身不是連通圖。這樣我們就只能建立碼頭了。

我們對于能建立碼頭的點,設置一個虛節點n+1。建立碼頭的費用就是到這個虛節點的費用。
對于第一種情況,有可能會有疑問,就是我們按照傳統的最小生成樹算法去做的話,會出現這一個點建立碼頭了,但是并沒有用到。例如:n=5,我們在4點建立了碼頭,這樣的話,我們在4和6之間建立了一條虛邊,假設是代價為1.4和5之間的代價為2,而在5這個點建立碼頭的代價為100.很顯然,我們在跑的時候,會先建立4和6之間的邊,在建立4和5之間的邊,5和6的邊時不會建立的。這樣4這里的碼頭不就白建了嗎。
對于這一疑問,我們要在兩點間建立碼頭的前提是,建立碼頭的總代價,是小于建立公路的代價的。也就是4->6的距離+5->6的距離小于4->5的距離的時候,才會在4和5建立碼頭。這樣的話,4->6的距離和5->6的距離,都小于4->5的距離,這樣跑最小生成樹才對。這就是為什么我們要取兩種情況(建立碼頭和不建立碼頭)的最小值。如果出現了上面的情況,建立碼頭出來的總代價一定是大于不建立碼頭的總代價的。一個注意的點是:如果這條邊是有收益的,無論如何都要建立。

代碼如下:

#include<bits/stdc++.h> #define ll long long using namespace std;const int maxx=1e6+100; const int maxn=1e4+100; struct node{int x,y,v;bool operator<(const node &a)const{return v<a.v;} }p[maxx]; int f[maxn],val[maxn]; int n,m;inline void init() {for(int i=1;i<=n+1;i++) f[i]=i; } inline int getf(int u) {return u==f[u]?u:f[u]=getf(f[u]); } inline void merge(int u,int v) {int t1=getf(u);int t2=getf(v);if(t1!=t2) f[t1]=t2; } inline bool check()//判斷聯通 {init();for(int i=1;i<=m;i++) merge(p[i].x,p[i].y);int x=getf(1);for(int i=1;i<=n;i++) if(getf(i)!=x) return 0;return 1; } inline int kruskal(int x,int y) {init();int sum=0;sort(p+1,p+1+y);for(int i=1;i<=y;i++){int t1=getf(p[i].x);int t2=getf(p[i].y);if(t1!=t2||p[i].v<0){sum+=p[i].v;f[t1]=t2;}}return sum; } int main() {scanf("%d%d",&n,&m);for(int i=1;i<=m;i++) scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].v);int k=m;for(int i=1;i<=n;i++){scanf("%d",&val[i]);if(val[i]!=-1){p[++k].x=n+1;p[k].y=i;p[k].v=val[i];}}if(check()) cout<<min(kruskal(n+1,k),kruskal(n,m));else cout<<kruskal(n+1,k)<<endl;return 0; }

努力加油a啊,(o)/~

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的问题 1437: [蓝桥杯][历届试题]城市建设(最小生成树)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。