bzoj2395: [Balkan 2011]Timeismoney
Description
有n个城市(编号从0..n-1),m条公路(双向的),从中选择n-1条边,使得任意的两个城市能够连通,一条边需要的c的费用和t的时间,定义一个方案的权值v=n-1条边的费用和*n-1条边的时间和,你的任务是求一个方案使得v最小
Input
第一行两个整数n,m,接下来每行四个整数a,b,c,t,表示有一条公路从城市a到城市b需要t时间和费用c
Output
【output】timeismoney.out
仅一行两个整数sumc,sumt,(sumc表示使得v最小时的费用和,sumc表示最小的时间和) 如果存在多个解使得sumc*sumt相等,输出sumc最小的
Sample Input
5 7
0 1 161 79
0 2 161 15
0 3 13 153
1 4 142 183
2 4 236 80
3 4 40 241
2 1 65 92
0 1 161 79
0 2 161 15
0 3 13 153
1 4 142 183
2 4 236 80
3 4 40 241
2 1 65 92
Sample Output
279 501
HINT
【数据规模】
1<=N<=200
1<=m<=10000
0<=a,b<=n-1
0<=t,c<=255
有5%的数据m=n-1
有40%的数据有t=c
对于100%的数据如上所述
题解:
终于知道什么是最小乘积生成树了
其实hnoi的画框 http://www.cnblogs.com/chenyushuo/p/5066481.html 也用了它的思想
code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #define maxn 205 7 #define maxm 10005 8 using namespace std; 9 char ch; 10 bool ok; 11 void read(int &x){ 12 for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1; 13 for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); 14 if (ok) x=-x; 15 } 16 int n,m; 17 int fa[maxn]; 18 int u[maxm],v[maxm],val[maxm],tim[maxm],cost[maxm]; 19 struct Point{ 20 int x,y; 21 bool operator==(Point b){return x==b.x&&y==b.y;} 22 }st,ed,ans; 23 struct Edge{ 24 int u,v,val,id; 25 }edge[maxm]; 26 bool cmp(Edge a,Edge b){return a.val<b.val;} 27 int find(int x){return x==fa[x]?fa[x]:fa[x]=find(fa[x]);} 28 Point kruskal(){ 29 for (int i=1;i<=m;i++) edge[i]=(Edge){u[i],v[i],val[i],i}; 30 sort(edge+1,edge+m+1,cmp); 31 for (int i=1;i<=n;i++) fa[i]=i; 32 int cnt=0; 33 Point ans; ans=(Point){0,0}; 34 for (int i=1;i<=m&&cnt<n;i++) 35 if (find(edge[i].u)!=find(edge[i].v)){ 36 fa[find(edge[i].u)]=find(edge[i].v); 37 cnt++,ans.x+=tim[edge[i].id],ans.y+=cost[edge[i].id]; 38 } 39 return ans; 40 } 41 Point calc(Point a,Point b){return a.x*a.y<b.x*b.y?a:b;} 42 Point solve(Point st,Point ed){ 43 Point mid; 44 for (int i=1;i<=m;i++) val[i]=tim[i]*(st.y-ed.y)-cost[i]*(st.x-ed.x); 45 mid=kruskal(); 46 if (st==mid||ed==mid) return calc(st,ed); 47 return calc(solve(st,mid),solve(mid,ed)); 48 } 49 int main(){ 50 read(n),read(m); 51 for (int i=1;i<=m;i++) read(u[i]),read(v[i]),u[i]++,v[i]++,read(tim[i]),read(cost[i]); 52 for (int i=1;i<=m;i++) val[i]=tim[i]; 53 st=kruskal(); 54 for (int i=1;i<=m;i++) val[i]=cost[i]; 55 ed=kruskal(); 56 ans=solve(st,ed); 57 printf("%d %d\n",ans.x,ans.y); 58 return 0; 59 }