妙啊,是一个逼近(?)的作法
把两个值最为平面上的点坐标,而后答案也是一个点。
首先求出多是答案的点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; }