[USACO][最短路]Cow Tours

Posted ggy778

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[USACO][最短路]Cow Tours相关的知识,希望对你有一定的参考价值。

题意:

farm(农庄)上有一堆pastures(牧场),cow path可以把一些牧场连起来,但是现在至少有两个牧场不能被任何cow path连起来。对于一对牧场,我们可以用一个cow path连起他们。一个牧场是一个点,一个cow path是一条边,牧场和cow path一同组成了一个区域“field”。field的diameter(对角线)被定义为field内所有点之中两两最短距离的最大值。

我们用坐标系刻画这一切,输入所有点的坐标以及一个描述边的邻接矩阵(点是不被认为有指向自己的边的,即邻接矩阵对角线都是0;是无向图,所以矩阵关于主对角线对称);要求我们找到两个点,使得这两个点连边之后形成的field的对角线长度最小,并输出此时对角线的长度。总之就是给若干个连通的无向图,且这俩无向图不连通,要我们加一条边让他俩连通并且连通完了的图任意两点之间的距离的最大值最小。即对于一系列图上用边相连的点,我们希望他们构成的{一些阵营A的边长之和+一些阵营B的边长之和+新加的边的边长}之中的最大值尽可能小。

思路:
暴力的话,首先通过一次dijkstra找到这两个图本身(随便选一个顶点做起点,能搜到的就染色,染色了的是一个阵营的,没染色的是另一个阵营的)。然后枚举改变_map矩阵的连通情况,每次都求一次dijkstra,然后输出最短路径数列d[]的最大值的最小情况时候d[]的最大值。这样,枚举连通要n^2复杂度,内嵌枚举起点是n,dijkstra是n^2的复杂度,总共是n^5的复杂度!!数据范围顶点数目N<=150,1秒实在捉急。试了一下,第五个点N=148的数据挂了....看来需要换个思路了。

考虑最终结果只有两种情况:已有的连通中最长的,或者连起来的新边边长+已有边长之中最短的。
于是对于第一种情况,可以把每个点出发连通的最大路径找到dia[i] = max(dia[i],cost[i][j]) | cost[i][j] != INF
计算第二种情况,对于每个不连通点,把他们连起来的长度为dia[i] + dist(nodes[i],nodes[j]) + dia[j]

之所以第一种要最长的,是因为已经floyd了i,j之间的最短路径。
之所以第二种新连的边之中选择了最短的,是因为要取得i,j之间最短距离。

其他想法:
给了坐标系,就想到“扫描线”这个名词:能不能只扫一遍坐标范围就得出图的直径呢?

/*
ID :ggy_7781
TASK :cowtour
LANG :C++11
*/

#include <bits/stdc++.h>
#define INF 0x3f3f3f
#define MAXN 150

using namespace std;
typedef long long ll;

struct Node
{
    int x,y;
};

int N;
Node nodes[MAXN];
double cost[MAXN][MAXN];
double dia[MAXN];

double dist(Node a,Node b)
{
    return sqrt((a.x - b.x)*(a.x-b.x)+(a.y - b.y)*(a.y-b.y));
}
int cmp(pair<int,int> p, pair<int,int> q)
{
    return dist(nodes[p.first],nodes[p.second]) < dist(nodes[q.first],nodes[q.second]);
}
int main(void)
{
    freopen("cowtour.in","r",stdin);
    freopen("cowtour.out","w",stdout);
    cin>>N;
    for(int i =0 ;i <N;i ++)
    {
        scanf("%d %d
",&nodes[i].x,&nodes[i].y);
    }
    char c;
    for(int i =0 ;i < N;i ++)
    {
        for(int j =0 ;j < N;j ++)
        {
            scanf("%c",&c);
            if(c == 1)
            {
                cost[i][j] = dist(nodes[i], nodes[j]);
            }
            else if(i != j)
            {
                cost[i][j] = INF;
            }
        }
        scanf("%c",&c);
    }
    for(int k = 0;k < N;k ++)
    {
        for(int i = 0;i < N;i ++)
        {
            for(int j = 0;j < N;j ++)
            {
                if(cost[i][k] + cost[k][j] < cost[i][j])
                {
                    cost[i][j] = cost[i][k] + cost[k][j];

                }
            }
        }
    }
    double l1 = 0;
    for(int i =0;i <N;i ++)
    {
        for(int j = 0;j< N;j ++)
        {
            if(cost[i][j] != INF)
            {
                dia[i] = max(dia[i],cost[i][j]);
                l1 = max(dia[i],l1);
            }
        }
    }
    double l2 = INF;
    for(int i =0 ;i < N;i ++)
    {
        for(int j =0 ;j < N;j ++)
        {
            if(cost[i][j] == INF)
            {
                l2 = min(l2,dia[i] + dist(nodes[i],nodes[j]) + dia[j]);
            }
        }
    }
    printf("%.6lf
",max(l1,l2));
    return 0;
}

 

以上是关于[USACO][最短路]Cow Tours的主要内容,如果未能解决你的问题,请参考以下文章

USACO 2.4 Cow Tours

BZOJ 1631 Usaco 2007 Feb. Cow Party

Luogu P2886 [USACO07NOV]牛继电器Cow Relays|最短路,倍增

[Luogu2901][USACO08MAR]牛慢跑Cow Jogging Astar K短路

Cow Navigation(USACO)

[USACO07NOV] Cow Relays