1. 程式人生 > >【BZOJ】2395: [Balkan 2011]Timeismoney

【BZOJ】2395: [Balkan 2011]Timeismoney

fine freopen 連接 bool air 不用 main CP 最小乘積生成樹

題解

最小乘積生成樹!

我們把,x的總和和y的總和作為x坐標和y左邊,畫在坐標系上

我們選擇兩個初始點,一個是最靠近y軸的A,也就是x總和最小,一個是最靠近x軸的B,也就是y總和最小
連接兩條直線,在這條直線上面的點都不用考慮了

我們選一個離直線最遠的點C,且在直線下方,我們用叉積考慮這個東西,也就是……面積最大!我們如果用最小生成樹的話,只要讓面積是負的就好了
推一下式子,發現是\((A.y - B.y) * C.x + (B.x - A.x) * C.y\)我們發現就是把邊設置成
\((A.y - B.y) * E[i].c + (B.x - A.x) * E[i].t\)做一遍最小生成樹

找到C點後遞歸處理A,C和C,B即可

邊界是兩點連線下方沒有點也就是叉積大於等於0

代碼

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <vector>
#include <set>
//#define ivorysi
#define eps 1e-8
#define mo 974711
#define pb push_back
#define mp make_pair #define pii pair<int,int> #define fi first #define se second #define MAXN 10005 #define space putchar(‘ ‘) #define enter putchar(‘\n‘) using namespace std; typedef long long int64; typedef unsigned int u32; typedef unsigned long long u64; typedef double db; const int64 MOD = 1000000007
; template<class T> void read(T &res) { res = 0;char c = getchar();T f = 1; while(c < ‘0‘ || c > ‘9‘) { if(c == ‘-‘) f = -1; c = getchar(); } while(c >= ‘0‘ && c <= ‘9‘) { res = res * 10 + c - ‘0‘; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) putchar(‘-‘); if(x >= 10) { out(x / 10); } putchar(‘0‘ + x % 10); } int N,M; struct Point { int64 x,y; int64 v; Point(){}; Point(int64 _x,int64 _y) { x = _x;y = _y;v = x * y; } friend bool operator < (const Point &a,const Point &b) { return a.v < b.v || (a.v == b.v && a.x < b.x); } }ans; struct Edge { int u,v; int64 c,t,w; Edge(){} Edge(int _u,int _v,int64 _c,int64 _t) { u = _u;v = _v;c = _c;t = _t; } friend bool operator < (const Edge &a,const Edge &b) { return a.w < b.w || (a.w == b.w && a.c < b.c); } }E[MAXN]; int fa[205]; int getfa(int u) { return fa[u] == u ? u : fa[u] = getfa(fa[u]); } Point kruskal() { sort(E + 1,E + M + 1); Point res = Point(0,0); for(int i = 1 ; i <= N ; ++i) fa[i] = i; for(int i = 1 ; i <= M ; ++i) { if(getfa(E[i].u) != getfa(E[i].v)) { fa[getfa(E[i].u)] = getfa(E[i].v); res.x += E[i].c;res.y += E[i].t; } } res.v = res.x * res.y; if(res < ans) ans = res; return res; } void Work(Point A,Point B) { for(int i = 1 ; i <= M ; ++i) { E[i].w = (A.y - B.y) * E[i].c + (B.x - A.x) * E[i].t; } Point r = kruskal(); if((A.x - r.x) * (B.y - r.y) - (A.y - r.y) * (B.x - r.x) >= 0) return; Work(A,r); Work(r,B); } void Solve() { read(N);read(M); int u,v; int64 c,t; for(int i = 1 ; i <= M ; ++i) { read(u);read(v);read(c);read(t); ++u;++v; E[i] = Edge(u,v,c,t); } ans.v = 1e18; for(int i = 1 ; i <= M ; ++i) { E[i].w = E[i].c; } Point A = kruskal(); for(int i = 1 ; i <= M ; ++i) { E[i].w = E[i].t; } Point B = kruskal(); Work(A,B); printf("%lld %lld\n",ans.x,ans.y); } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Solve(); return 0; }

【BZOJ】2395: [Balkan 2011]Timeismoney