Applese 的毒氣炸彈 G 牛客寒假算法基礎集訓營4(圖論+最小生成樹)
阿新 • • 發佈:2019-01-30
line rmi 連通 include 示例 scribe ges prev form
空間限制:C/C++ 262144K,其他語言524288K
64bit IO Format: %lld
眾所周知,Applese 是個很強的選手,它的化學一定很好。
今天他又AK了一套題覺得很無聊,於是想做個毒氣炸彈玩。
毒氣炸彈需要 k 種不同類型元素構成,Applese一共有 n 瓶含有這些元素的試劑。
已知元素混合遵循 m 條規律,每一條規律都可以用 "x y c" 描述。
表示將第 x 瓶試劑混入第 y 瓶試劑或者把第 y 瓶試劑混入第 x 瓶試劑,需要消耗 c 的腦力。
特別地,除了這 m 條規律外,Applese 可以將任意兩瓶相同元素的試劑混合,且不需要消耗腦力。
Applese 想要配出毒氣炸彈,就需要使 S 中含有 1∼k1∼k 這 k 種元素。它想知道自己最少花費多少腦力可以把毒氣炸彈做出來。
鏈接:https://ac.nowcoder.com/acm/contest/330/G
來源:牛客網
空間限制:C/C++ 262144K,其他語言524288K
64bit IO Format: %lld
題目描述
眾所周知,Applese 是個很強的選手,它的化學一定很好。
今天他又AK了一套題覺得很無聊,於是想做個毒氣炸彈玩。
毒氣炸彈需要 k 種不同類型元素構成,Applese一共有 n 瓶含有這些元素的試劑。
已知元素混合遵循 m 條規律,每一條規律都可以用 "x y c" 描述。
表示將第 x 瓶試劑混入第 y 瓶試劑或者把第 y 瓶試劑混入第 x 瓶試劑,需要消耗 c 的腦力。
特別地,除了這 m 條規律外,Applese 可以將任意兩瓶相同元素的試劑混合,且不需要消耗腦力。
Applese 想要配出毒氣炸彈,就需要使 S 中含有 1∼k1∼k 這 k 種元素。它想知道自己最少花費多少腦力可以把毒氣炸彈做出來。
輸入描述:
第一行為三個整數 n, m, k 表示 Applese 擁有的試劑的數量,混合規律的數量和所需的元素種類數。
第二行為 n 個整數 a1,a2,…,ana1,a2,…,an,分別表示每一瓶試劑的元素類型。接下來m行,每行三個整數 x, y, c,含義如題目描述中所述。不保證 x, y的試劑種類不同。
輸出描述:
輸出一個正整數表示最小的耗費腦力。特別地,如果無法合成出毒氣炸彈,輸出 "-1"。示例1
輸入
復制6 8 2 1 1 1 2 2 2 1 2 1 2 3 2 1 3 3 3 4 6 4 5 1 4 6 3 5 6 2 1 6 2
輸出
復制2
備註:
1≤n,k,m≤1051≤n,k,m≤105
1≤x,y≤n,x≠y1≤x,y≤n,x≠y1≤c≤109
思路:
看成一張圖,就是把同類元素的試劑當作一個點之後,求這個圖的最小生成樹。
然後用你最喜歡的求MST的算法求解就好。註意判不連通的情況。
細節見代碼
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #define rt return #define sz(a) int(a.size()) #define all(a) a.begin(), a.end() #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define pii pair<int,int> #define pll pair<long long ,long long> #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define MS0(X) memset((X), 0, sizeof((X))) #define MSC0(X) memset((X), ‘\0‘, sizeof((X))) #define pb push_back #define mp make_pair #define fi first #define se second #define eps 1e-6 #define gg(x) getInt(&x) #define db(x) cout<<"== [ "<<x<<" ] =="<<endl; using namespace std; typedef long long ll; ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} ll lcm(ll a,ll b){return a/gcd(a,b)*b;} ll powmod(ll a,ll b,ll MOD){ll ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;} inline void getInt(int* p); const int maxn=1000010; const int inf=0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/ struct Edge { int f,t,w; Edge(){} Edge(int ff,int tt,int ww) { f=ff; t=tt; w=ww; } }; std::vector<Edge> edge; bool cmp(Edge a,Edge b) { return a.w<b.w; } // 並查集部分 int fa[maxn]; int findpar(int x) { if(fa[x]==x) return x; else return fa[x]=findpar(fa[x]); } void initufs(int n) { repd(i,1,n) { fa[i]=i; } } int n,m,k; // int a[maxn]; ll Kruskal() { ll res=0ll; initufs(n); int cnt=0;// 記錄了MST加入了幾個節點 for(int i=0;i<edge.size();i++) { int u=findpar(edge[i].f); int v=findpar(edge[i].t); if(u==v) continue; fa[u]=v; // merge res+=edge[i].w; cnt++; if(cnt==k-1) // 已經加滿了樹 break; } if(cnt!=k-1) return -1; else return res; } int main() { scanf("%d %d %d",&n,&m,&k); repd(i,1,n) { scanf("%d",&a[i]); } int u,v,w; repd(i,1,m) { scanf("%d %d %d",&u,&v,&w); u=a[u];v=a[v]; if(u==v) continue; if(u>=1&&u<=k&&v>=1&&v<=k) { edge.push_back(Edge(u,v,w)); } } sort(edge.begin(),edge.end(),cmp); ll res=Kruskal(); printf("%lld\n",res ); return 0; } inline void getInt(int* p) { char ch; do { ch = getchar(); } while (ch == ‘ ‘ || ch == ‘\n‘); if (ch == ‘-‘) { *p = -(getchar() - ‘0‘); while ((ch = getchar()) >= ‘0‘ && ch <= ‘9‘) { *p = *p * 10 - ch + ‘0‘; } } else { *p = ch - ‘0‘; while ((ch = getchar()) >= ‘0‘ && ch <= ‘9‘) { *p = *p * 10 + ch - ‘0‘; } } }
Applese 的毒氣炸彈 G 牛客寒假算法基礎集訓營4(圖論+最小生成樹)