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;
}
原文地址:https://www.cnblogs.com/zbtrs/p/7726133.html