題意:noi2014魔法森林弱化版QwQ,最小化\(max(g_i)*G + max(s_i)*S\)的最小生成樹ios
考慮按g升序加邊,用已在生成樹中的邊和新加入的邊求當前最小生成樹。spa
複雜度\(O(nm)\)code
vector真好用ci
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <vector> using namespace std; typedef long long ll; const int N = 205, M = 50005; const ll inf = 2e18+5; inline int read() { int x = 0, f = 1; char c = getchar(); while(c<'0' || c>'9') {if(c=='-') f=-1; c=getchar();} while(c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();} return x*f; } int n, m, G, S; struct edge { int x, y, g, s; bool operator <(const edge &r) const { return g < r.g; } } e[M]; bool cmp_s(const edge &a, const edge &b) { return a.s < b.s; } int fa[N]; int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);} vector<edge> v; vector<edge>::iterator it; ll ans = inf; ll kruskal(int m) { //printf("kruskal %d\n", m); int mg = 0, ms = 0; for(int i=1; i<=n; i++) fa[i] = i; int cnt = 0; for(it = v.begin(); it != v.end(); ) { int x = find(it->x), y = find(it->y); //printf("%d %d %d %d\n", e[i].x, e[i].y, x, y); cout << endl; if(x == y) { it = v.erase(it); continue; } fa[y] = x; mg = max(mg, it->g); ms = max(ms, it->s); if(++cnt == n-1) break; it++; } if(cnt == n-1) return (ll) mg * G + (ll) ms * S; else return inf; } void solve() { sort(e+1, e+1+m); for(int i=1; i<=n-2; i++) v.push_back(e[i]); sort(v.begin(), v.end(), cmp_s); for(int p=n-1; p<=m; p++) { //printf("ppp %d\n", p); edge now = e[p]; int flag = 0; for(it = v.begin(); it != v.end(); it++) { if(it->s > now.s) { v.insert(it, now); flag = 1; break; } } if(!flag) v.insert(it, now); ans = min(ans, kruskal(p)); } if(ans == inf) ans = -1; cout << ans; } int main() { //freopen("in", "r", stdin); cin >> n >> m >> G >> S;; for(int i=1; i<=m; i++) { e[i].x = read(); e[i].y = read(); e[i].g = read(); e[i].s = read(); } solve(); }