zoukankan      html  css  js  c++  java
  • noip模拟赛 radius

    分析:这道题实在是不好想,一个可以骗分的想法是假定要求的那个点在中心点上,可以骗得不少分.但是在边上的点要怎么确定呢?理论复杂度O(﹢无穷).答案一定是和端点有关的,涉及到最大值最小,考虑二分最大值,关键就是怎么check.如果有一条边x,还有一个点y,把y到x上的点的距离>mid的点给标记上,这样就会形成许多个区间,判断一下x是否被这些区间给完全覆盖住了,如果没有被完全覆盖住,证明这个最大值可以更小.思路非常奇妙,具体实现细节可以参看代码:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 210, maxm = 40010;
    
    int n, m, a[maxn][maxn], head[maxn], to[maxm],ans,len,top,nextt[maxm],w[maxm], tot = 1;
    struct node
    {
        int x, y, z;
    }e[20000];
    
    struct node2
    {
        int first, second;
    }e2[20000];
    
    void add(int x, int y, int z)
    {
        w[tot] = z;
        to[tot] = y;
        nextt[tot] = head[x];
        head[x] = tot++;
    }
    
    void floyd()
    {
        for (int k = 1; k <= n; k++)
            for (int i = 1; i <= n; i++)
                for (int j = 1; j <= n; j++)
                    if (a[i][j] > a[i][k] + a[k][j])
                        a[i][j] = a[i][k] + a[k][j];
    }
    
    void add2(int x, int y)
    {
        e2[++top].first = x;
        e2[top].second = y;
    }
    
    bool cmp(node2 a, node2 b)
    {
        if (a.first == b.first)
            return a.second < b.second;
        return a.first < b.first;
    }
    
    bool can()
    {
        int x = 0;
        sort(e2 + 1, e2 + 1 + top,cmp); 
        for (int i = 1; i <= top; i++)
        {
            if (x < e2[i].first)
                return false;
            if (x > e2[i].second)
                continue;
            x = e2[i].second + 1;
        }
        if (x > len)
            return true;
        return false;
    }
    
    bool check(int p)
    {
        bool flag = false;
        for (int i = 1; i <= m; i++)
        {
            top = 0;
            len = e[i].z;
            for (int j = 1; j <= n; j++)
            {
                int x = p - a[e[i].x][j];
                int y = p - a[e[i].y][j];
                if (x < 0 && y < 0)
                {
                    add2(0, e[i].z);
                    break;
                }
                if (x >= e[i].z || y >= e[i].z)
                    continue;
                if (x + y >= e[i].z)
                    continue;
                add2(max(0, x + 1), min(e[i].z, e[i].z - y - 1));
            }
            if (!can())
                flag = 1;
            if (flag)
                break;
        }
        if (flag)
            return true;
        return false;
    }
    
    int main()
    {
        memset(a, 127 / 3, sizeof(a)); 
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= m; i++)
        {
            int u, v, z;
            scanf("%d%d%d", &u, &v, &z);
            z *= 2;
            add(u, v, z);
            add(v, u, z);
            e[i].x = u;
            e[i].y = v;
            e[i].z = z;
            a[u][v] = a[v][u] = min(a[u][v], z);
        }
        for (int i = 1; i <= n; i++)
            a[i][i] = 0;
        floyd();
        int l = 0, r = 10000010;
        while (l <= r)
        {
            int mid = (l + r) >> 1;
            if (check(mid))
            {
                ans = mid;
                r = mid - 1;
            }
            else
                l = mid + 1;
        }
        double temp = ans / 2.0;
        printf("%.2lf
    ", temp);
    return 0;
    }
  • 相关阅读:
    BZOJ 3506 机械排序臂 splay
    BZOJ 2843 LCT
    BZOJ 3669 魔法森林
    BZOJ 2049 LCT
    BZOJ 3223 文艺平衡树 splay
    BZOJ 1433 假期的宿舍 二分图匹配
    BZOJ 1051 受欢迎的牛 强连通块
    BZOJ 1503 郁闷的出纳员 treap
    BZOJ 1096 ZJOI2007 仓库设计 斜率优化dp
    BZOJ 1396: 识别子串( 后缀数组 + 线段树 )
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7726133.html
Copyright © 2011-2022 走看看