Assume that each vertex has two weights, X and Y. Calculate a spanning tree to minimize sigma (X [I]) * sigma (Y [I.
Set each spanning tree as a point in the coordinate system, SIGMA (X [I]) as the abscissa, and Sigma (Y [I]) as the ordinate. The problem is converted to finding a vertex to minimize xy = K. That is, the inverse proportional Function Y = K/x over this point is closest to the coordinate axis.
Step 1: Obtain the Spanning Tree (points) closest to the X axis and Y axis respectively: A and B (create the smallest spanning tree based on the X and Y weights respectively ).
Step 2: Search for the Spanning Tree C nearest to the origin of AB and try to update the answer.
[How to Find ????
-- Because c is the farthest from AB, s △abc has the largest area.
Vector AB = (B. X-A. X, B. Y-A. Y)
Vector AC = (C. X-A. X, C. Y-A. Y)
The cross product (1/2 of the vector AB and AC) is the area of S △abc (except that the cross product is backward and negative, so this value is minimized, that is, to maximize the area ).
Minimal :( B. x-A.x) * (C. y-A.y)-(B. y-A.y) * (C. x-A.x)
= (B. x-A.x) * C. Y + (. y-B.y) * C. x-. y * (B. x-A.x) +. x * (B. y-A.y)/* Bold is constant, do not care */
Therefore, change the weight of each vertex to Y [I] * (B. x-A.x) +. y-B.y) * X [I] for the smallest Spanning Tree, find is C.]
Step 3: Recursively search for the AC and BC sides that are close to the origin. Recursive border: This side has no vertices (that is, the cross area is greater than or equal to zero ).
Bzoj2395 bare answer
Code:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 int res; 6 char c; 7 inline int Get() 8 { 9 res=0;c=‘*‘;10 while(c<‘0‘||c>‘9‘)c=getchar();11 while(c>=‘0‘&&c<=‘9‘){res=res*10+(c-‘0‘);c=getchar();}12 return res;13 }14 struct Edge{int u,v,c,t,w;void read(){u=Get();v=Get();c=Get();t=Get();}};15 struct Point{int x,y;Point(const int &A,const int &B){x=A;y=B;}Point(){}};16 typedef Point Vector;17 typedef long long LL;18 Vector operator - (const Point &a,const Point &b){return Vector(a.x-b.x,a.y-b.y);}19 int Cross(Vector A,Vector B){return A.x*B.y-A.y*B.x;}20 bool operator < (const Edge &a,const Edge &b){return a.w<b.w;}21 Edge edges[10001];22 int n,m,rank[201],fa[201];23 Point ans=Point(1000000000,1000000000),minc,mint;24 inline void init()25 {26 memset(rank,0,sizeof(rank));27 for(int i=0;i<n;i++)28 fa[i]=i;29 }30 int findroot(int x) 31 {32 if(fa[x]==x)33 return x;34 int t=findroot(fa[x]);35 fa[x]=t;36 return t;37 }38 inline void Union(int U,int V)39 {40 if(rank[U]<rank[V])41 fa[U]=V;42 else43 {44 fa[V]=U;45 if(rank[U]==rank[V])46 rank[U]++;47 }48 }49 inline Point Kruscal()50 {51 int tot=0;52 Point now=Point(0,0);53 init();54 for(int i=1;i<=m;i++)55 {56 int U=findroot(edges[i].u),V=findroot(edges[i].v);57 if(U!=V)58 {59 Union(U,V);60 tot++;61 now.x+=edges[i].c;62 now.y+=edges[i].t;63 if(tot==n-1)64 break;65 }66 }67 LL Ans=(LL)ans.x*ans.y,Now=(LL)now.x*now.y;68 if( Ans>Now || (Ans==Now&&now.x<ans.x) )69 ans=now;70 return now;71 }72 void Work(Point A,Point B)73 {74 for(int i=1;i<=m;i++)75 edges[i].w=edges[i].t*(B.x-A.x)+edges[i].c*(A.y-B.y);76 sort(edges+1,edges+m+1);77 Point C=Kruscal();78 if(Cross(B-A,C-A)>=0)79 return;80 Work(A,C);81 Work(C,B);82 }83 int main()84 {85 scanf("%d%d",&n,&m);86 for(int i=1;i<=m;i++)87 edges[i].read();88 for(int i=1;i<=m;i++)89 edges[i].w=edges[i].c;90 sort(edges+1,edges+m+1);91 minc=Kruscal();92 for(int i=1;i<=m;i++)93 edges[i].w=edges[i].t;94 sort(edges+1,edges+m+1);95 mint=Kruscal();96 Work(minc,mint);97 printf("%d %d\n",ans.x,ans.y);98 return 0;99 }
[Minimum product Spanning Tree] bzoj2395 [Balkan 2011] timeismoney