BZOJ 2395 [Balkan 2011]Time is money

题面

题解

\(\sum_i c_i\)\(\sum_i t_i\)分别看做分别看做\(x\)\(y\),投射到平面直角坐标系中,于是就是找\(xy\)最小的点

于是可以先找出\(x\)最小的点\(\mathrm{A}\)\(y\)最小的点\(\mathrm{B}\),然后找到在\(\mathrm{AB}\)左下方的最远的点\(\mathrm{C}\),如图所示:

5c6bb9bf533ea.png

\(\overrightarrow{\mathrm{AB}} \times \overrightarrow{\mathrm{AC}}\)最小(因为\(\overrightarrow{\mathrm{AB}} \times \overrightarrow{\mathrm{AC}} \leq 0\)
\[ \begin{aligned} \because \overrightarrow{\mathrm{AB}} \times \overrightarrow{\mathrm{AC}} &= (x_{\mathrm{B}} - x_{\mathrm{A}})(y_{\mathrm{C}} - y_{\mathrm{A}}) - (y_{\mathrm{B}} - y_{\mathrm{A}})(x_\mathrm{C} - x_\mathrm{A}) \\ &= (x_\mathrm B - x_\mathrm A) \times y_\mathrm C + (y_\mathrm A - y_\mathrm B) \times x_\mathrm C + y_\mathrm B x_\mathrm A - x_\mathrm B y_\mathrm A \end{aligned} \]
然后发现只要\((x_\mathrm B - x_\mathrm A) \times y_\mathrm C + (y_\mathrm A - y_\mathrm B) \times x_\mathrm C\)最小即可。

将每条边的权值改为\(\mathrm{g}[i][j] = (y_\mathrm A - y_\mathrm B) \times c[i][j] + (x_\mathrm B - x_\mathrm A)\times t[i][j]\),跑一遍最小生成树就可以得出答案了。

找到\(\mathrm C\)之后用叉积判断一下\(\mathrm C\)是不是在\(\mathrm{AB}\)的下方,如果是的话,就递归处理\(\mathrm{AC, CB}\)

复杂度?O(能过)

因为\(\mathrm{A, B, C}\)肯定在凸包上,又\(n\)个点的凸包期望点数为\(\sqrt{\ln n}\)

于是复杂度为\(\mathrm{O}(\sqrt{\ln n!} \times n^2)\)或者\(\mathrm{O}(\sqrt{\ln n!} \times m\log m)\)

代码

#include<cstdio>
#include<cctype>
#include<algorithm>
#define RG register

const int N(210), INF(1e9);
struct vector { int x, y; };
vector ans = (vector) {INF, INF};
inline vector operator - (const vector &lhs, const vector &rhs)
    { return (vector) {lhs.x - rhs.x, lhs.y - rhs.y}; }
inline int operator * (const vector &lhs, const vector &rhs)
    { return lhs.x * rhs.y - lhs.y * rhs.x; }
int g[N][N], f[N][N], dis[N], c[N][N], t[N][N], cdis[N], tdis[N], vis[N], n, m;

vector prim(int valx, int valy)
{
    for(RG int i = 1; i <= n; i++)
        for(RG int j = 1; j <= n; j++)
            if(f[i][j]) g[i][j] = valx * c[i][j] + valy * t[i][j];
    std::fill(dis + 1, dis + n + 1, INF);
    std::fill(vis + 1, vis + n + 1, 0);
    dis[1] = cdis[1] = tdis[1] = 0;
    vector res = (vector) {0, 0};
    for(RG int i = 1; i <= n; i++)
    {
        int _min = INF, x = -1;
        for(RG int j = 1; j <= n; j++)
            if(_min > dis[j] && (!vis[j])) _min = dis[j], x = j;
        if(_min == INF) break; vis[x] = 1;
        res.x += cdis[x], res.y += tdis[x];
        for(RG int j = 1; j <= n; j++) if(f[x][j])
            if(dis[j] > g[x][j]) dis[j] = g[x][j],
                cdis[j] = c[x][j], tdis[j] = t[x][j];
    }
    long long sum = 1ll * res.x * res.y, _min = 1ll * ans.x * ans.y;
    if(sum < _min || (sum == _min && res.x < ans.x)) ans = res;
    return res;
}

void solve(const vector &A, const vector &B)
{
    vector C = prim(A.y - B.y, B.x - A.x);
    if((B - A) * (C - A) >= 0) return;
    solve(A, C); solve(C, B);
}

int main()
{
    scanf("%d%d", &n, &m);
    for(RG int i = 1, x, y, _c, _t; i <= m; i++)
        scanf("%d%d%d%d", &x, &y, &_c, &_t), ++x, ++y,
        c[x][y] = c[y][x] = _c, t[x][y] = t[y][x] = _t,
        f[x][y] = f[y][x] = 1;
    vector A = prim(1, 0), B = prim(0, 1);
    solve(A, B); printf("%d %d\n", ans.x, ans.y);
    return 0;
}

转载于:https://www.cnblogs.com/cj-xxz/p/10401868.html

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值