2395: [Balkan 2011]Timeismoney

阅读: 评论:0

2395: [Balkan 2011]Timeismoney

2395: [Balkan 2011]Timeismoney

2395: [Balkan 2011]Timeismoney

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 659 Solved: 359
[Submit][Status][Discuss]
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%的数据如上所述

Source

[Submit][Status][Discuss]

这就是一个裸的最小乘积生成树
对于这类问题,貌似有个统称叫做乘积规划
反正都是能用一类方法解决的
将每种合法的生成树方案看做二维平面上的一个点 (x,y)
其中 x 等于所选边的费用和,y等于所选边的时间和
那么目标等价于使得 k=xy 取得最小值
即让函数 y=kx 尽可能地贴近坐标轴
将所有点画在平面上,那么最优解一定存在与左下角的凸包上
考虑如何求出这块区域上的点
一开始先确定两种方案,记 A 为令x最小的方案, B 为令y最小的方案
那么一定是在直线 AB 左下方的点才可能出现在凸包
找到一个点 C ,使得它尽可能贴近坐标轴
那么这个点C一定是尽量离 AB 远一些
于是就等价于 SΔABC 尽量大
即 AB→×AC→ 取最小值
暴力展开一下上面的式子就会发现。。。
真的变成做一棵最小生成树了
特别地,如果最小生成树权值为非负数,说明找不到这样的点了
递归解决 (A,C) 和 (C,B) 就行了
注:随机情况下 n 个点凸包上的点数期望是lnn−−−√
那么复杂度就十分科学了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;const int maxn = 202;
const int maxm = 1E4 + 10;
typedef long long LL;struct E{int a,b,x,y; E(){}E(int a,int b,int x,int y): a(a),b(b),x(x),y(y){}bool operator < (const E &B) const {return x < B.x;}
}e[maxm],_e[maxm];struct Point{int x,y; Point(){}Point(int x,int y): x(x),y(y){}bool operator < (const Point &B){if (1LL * x * y < 1LL * B.x * B.y) return 1;if (1LL * x * y > 1LL * B.x * B.y) return 0;return x < B.y;}
}Ans;int n,m,cnt,fa[maxn],vis[maxm];inline int getfa(int k) {return k == fa[k] ? k : fa[k] = getfa(fa[k]);}inline void Kruskal(Point &C,int dx,int dy,int delta)
{for (int i = 0; i < n; i++) fa[i] = i; ++cnt;for (int i = 1; i <= m; i++)_e[i] = E(e[i].a,e[i].b,dx * e[i].x + dy * e[i].y,i);LL sum = 0; sort(_e + 1,_e + m + 1);for (int i = 1; i <= m; i++){E k = _e[i];int fx = getfa(k.a),fy = getfa(k.b);if (fx == fy) continue;fa[fx] = fy; sum += 1LL * k.x; vis[k.y] = cnt; }sum += 1LL * delta; C = Point(0,0);if (sum >= 0) {C = Point(-1,-1); return;}for (int i = 1; i <= m; i++)if (vis[i] == cnt) C.x += e[i].x,C.y += e[i].y;
}void Pre_Work(Point &C,int dx,int dy)
{C = Point(0,0); ++cnt;for (int i = 0; i < n; i++) fa[i] = i;for (int i = 1; i <= m; i++)_e[i] = E(e[i].a,e[i].b,dx * e[i].x + dy * e[i].y,i);sort(_e + 1,_e + m + 1);for (int i = 1; i <= m; i++){E k = _e[i];int fx = getfa(k.a),fy = getfa(k.b);if (fx == fy) continue;fa[fx] = fy; vis[k.y] = cnt;}for (int i = 1; i <= m; i++)if (vis[i] == cnt) C.x += e[i].x,C.y += e[i].y;
}inline void Dfs(Point A,Point B)
{Point C; int now;now = A.x * B.y - B.x * A.y;Kruskal(C,A.y - B.y,B.x - A.x,now);if (C.x == -1 && C.y == -1) return;if (C < Ans) Ans = C; Dfs(A,C); Dfs(C,B);
}inline int getint()
{char ch = getchar(); int ret = 0;while (ch < '0' || '9' < ch) ch = getchar();while ('0' <= ch && ch <= '9')ret = ret * 10 + ch - '0',ch = getchar();return ret;
}int main()
{#ifdef DMCfreopen(&#","r",stdin);#endifn = getint(); m = getint();for (int i = 1; i <= m; i++){int a,b,x,y;a = getint(); b = getint();x = getint(); y = getint();e[i] = E(a,b,x,y);}Point A,B; Pre_Work(A,1,0); Pre_Work(B,0,1);Ans = A; if (B < Ans) Ans = B;Dfs(A,B); printf("%d %dn",Ans.x,Ans.y);return 0;
}

本文发布于:2024-02-04 22:18:06,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170717671960113.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:Balkan   Timeismoney
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23