NOIP 2007 Senior 4

来源:互联网 发布:淘宝客怎么设置 编辑:程序博客网 时间:2024/05/29 15:13

传送门(洛谷)

这道题,数据规模相当小,n三次方随便搞,所以我们就先考虑求直径。
我们直接 O(n^3) Floyd 好了,然后 O(n ^ 2) 枚举直径端点。

设直径端点为u,v。如果有 floyd[u][i] + floyd[i][v] = floyd[u][v]我们就知道了 i 在直径上了。
于是我们又 O(n^2) 枚举点对,若两个点都在直径上并且距离小于S,它可能就是一个核了。所以怎么求偏心距呢?
离“准核”最远的点一定是直径的端点,否则它就不是直径端点了(因为有更远的)。所以可以 O(1) 查询。枚举核的时间复杂度 O(n^2)。
但是这是可以 hack 的。如果核的端点为直径的端点,偏心距显然不是0。因此特判一下,若枚举的“准核”为直径,就再用一个 O(n^2) 的算法求 ecc。具体点,一个枚举直径外的点,一个枚举直径内的点。

算法时间复杂度为 O(n^3) | O(n^2)。最主要的一点就是发现离“准核”最远的点一定是直径的端点,否则只能用 O(n^4) 甚至更高时间复杂度的算法。

参考代码

#include <cstdio>#include <cstdlib>#include <cmath>#include <cstring>#include <iostream>#include <algorithm>#include <vector>#include <string>#include <stack>#include <queue>#include <deque>#include <map>#include <set>#include <bitset>typedef int INT;using std::cin;using std::cout;using std::endl;inline INT readIn(){    INT a = 0;    bool minus = false;    char ch = getchar();    while (!(ch == '-' || (ch >= '0' && ch <= '9'))) ch = getchar();    if (ch == '-')    {        minus = true;        ch = getchar();    }    while (ch >= '0' && ch <= '9')    {        a = a * 10 + (ch - '0');        ch = getchar();    }    if (minus) a = -a;    return a;}inline void printOut(INT x){    char buffer[15];    INT length = 0;    bool minus = x < 0;    if (minus) x = -x;    do    {        buffer[length++] = x % 10 + '0';        x /= 10;    } while (x);    if (minus) buffer[length++] = '-';    do    {        putchar(buffer[--length]);    } while (length);    putchar('\n');}const INT INF = (~(INT(1) << (sizeof(INT) * 8 - 1)));const INT maxn = 305;INT n, s;INT rect[maxn][maxn];void run(){    n = readIn();    s = readIn();    memset(rect, 0x3f, sizeof(rect));    for (int i = 1; i <= n; i++) rect[i][i] = 0;    for (int i = 1; i < n; i++)    {        INT u = readIn();        INT v = readIn();        INT c = readIn();        rect[u][v] = rect[v][u] = c;    }    for (int k = 1; k <= n; k++)        for (int i = 1; i <= n; i++)            for (int j = 1; j <= n; j++)                if (i != j && j != k && k != i)                    rect[i][j] = std::min(rect[i][j], rect[i][k] + rect[k][j]);    INT maxLen = 0;    INT u, v;    for (int i = 1; i <= n; i++)        for (int j = i + 1; j <= n; j++)        {            if (rect[i][j] > maxLen)            {                u = i;                v = j;                maxLen = rect[i][j];            }        }    INT ans = INF;    for (int i = 1; i <= n; i++)        if (rect[u][i] + rect[i][v] == maxLen)            for (int j = i; j <= n; j++)                if (rect[i][j] <= s && rect[u][j] + rect[j][v] == maxLen)                {                    if (i != u || j != v)                        ans = std::min(ans, std::max(std::min(rect[u][i], rect[u][j]), std::min(rect[v][i], rect[v][j])));                    else                    {                        INT ecc = 0;                        for (int a = 1; a <= n; a++)                        {                            INT temp = INF;                            if (rect[u][a] + rect[a][v] == maxLen) continue;                            for (int b = 1; b <= n; b++)                                if (rect[u][b] + rect[b][v] == maxLen)                                    temp = std::min(temp, rect[a][b]);                            ecc = std::max(ecc, temp);                        }                        ans = std::min(ans, ecc);                    }                }    printOut(ans);}int main(){    run();    return 0;}
原创粉丝点击