• 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 }
  • 相关阅读:
    家庭记账本APP开发准备(二)
    使用花生壳5做内网穿透
    课堂练习之可视化的强化版
    第五周总结
    课堂练习之疫情可视化
    第四周总结
    第三周总结
    第二周总结
    课堂练习之最大子数组
    软工第二学期开课博客
  • 原文地址:https://www.cnblogs.com/chenyushuo/p/5122484.html
Copyright © 2020-2023  润新知