妙啊,是一個逼近(?)的作法
把兩個值最爲平面上的點座標,而後答案也是一個點。
首先求出多是答案的點xy分別是按照c和t排序作最小生成樹的答案,而後考慮比這兩個點的答案小的答案,必定在xy連線靠近原電一側(不過這部分並不全都能更新答案),而後最小的必定是距離xy連線最遠的,設爲點z,也就是三角形xyz面積最大,而後用叉積列出面積公式嗎,按這個作一次最小生成樹求出z並更新答案,而後遞歸處理(x,z)(z,y),直到z不在靠近原點一側ios
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int N=505; int n,m,f[N]; pair<int,int>ans=make_pair(1e9,1e9); struct qwe { int u,v,c,t,w; }a[10005]; bool cmp(const qwe &a,const qwe &b) { return a.w<b.w; } int read() { int r=0,f=1; char p=getchar(); while(p>'9'||p<'0') { if(p=='-') f=-1; p=getchar(); } while(p>='0'&&p<='9') { r=r*10+p-48; p=getchar(); } return r*f; } int zhao(int x) { return x==f[x]?x:f[x]=zhao(f[x]); } pair<int,int>mst() { sort(a+1,a+1+m,cmp); for(int i=1;i<=n;i++) f[i]=i; pair<int,int>r=make_pair(0,0); for(int i=1,con=0;i<=m&&con<n-1;i++) { int fu=zhao(a[i].u),fv=zhao(a[i].v); if(fu!=fv) {//cerr<<a[i].u<<" "<<a[i].v<<endl; f[fu]=fv; con++; r.first+=a[i].c,r.second+=a[i].t; } }//cerr<<r.first<<" "<<r.second<<endl<<endl; if(1ll*r.first*r.second<1ll*ans.first*ans.second||(1ll*r.first*r.second==1ll*ans.first*ans.second&&r<ans)) ans=r; return r; } void wk(pair<int,int>x,pair<int,int>y) {//cerr<<x.first<<" "<<x.second<<" "<<y.first<<" "<<y.second<<endl; for(int i=1;i<=m;i++) a[i].w=a[i].t*(y.first-x.first)-a[i].c*(y.second-x.second); pair<int,int>z=mst(); if((y.first-x.first)*(z.second-x.second)-(y.second-x.second)*(z.first-x.first)>=0) return; wk(x,z); wk(z,y); } int main() { n=read(),m=read(); for(int i=1;i<=m;i++) a[i].u=read()+1,a[i].v=read()+1,a[i].c=read(),a[i].t=read(); for(int i=1;i<=m;i++) a[i].w=a[i].c; pair<int,int>x=mst(); for(int i=1;i<=m;i++) a[i].w=a[i].t; pair<int,int>y=mst(); wk(x,y); printf("%d %d\n",ans.first,ans.second); return 0; }