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

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
",ans.x,ans.y);
58     return 0;
59 }
原文地址:https://www.cnblogs.com/chenyushuo/p/5122484.html