【USACO2.4.3】【洛谷P1522】牛的旅行【最短路】【并查集】

news/2024/11/29 11:34:30/

题目大意:

题目链接:

USACO:http://train.usaco.org/usacoprob2?a=TyEfGmq7aAo&S=cowtour
洛谷:https://www.luogu.org/problemnew/show/P1522

有一个无向图,可以在两个不同的联通块中选择其中两个结点并连接,求此时的新联通块的最远两点之间的距离的最小值。


思路:

n ≤ 150 n\leq150 n150的数据很明显是在提示我们用 F l o y d Floyd Floyd做。那么我们就可以求出任意两点之间的距离。
此时可以选择枚举任意两点 i , j i,j i,j,如果这两点不在一个联通块( d i s [ i ] [ j ] > I n f dis[i][j]>Inf dis[i][j]>Inf),那么就可以 O ( n ) O(n) O(n)求出这两个点和同一联通块的最远点之间的距离,然后更新答案
a n s = m i n ( a n s , s u m 1 + s u m 2 + c a l ( i , j ) ) ans=min(ans,sum1+sum2+cal(i,j)) ans=min(ans,sum1+sum2+cal(i,j))
最终取个 6 6 6位小数就可以了。
然后就可以得到 90 90 90分的高分。
此时再打个表就过了


关于# 7 7 7

它死了。
为什么会这样呢?
我们发现,每次更新 a n s ans ans的时候,是把新联通块的新加入的边看成最长路径中的一条了。那么有没有可能加入这条边之后最长路依然只存在其中的一个旧联通块中呢?
有可能。
那么就得先把所有联通块的最长路求出来,然后再更新 a n s ans ans的时候再加入两个条件:
a n s = m i n ( a n s , m a x ( s u m 1 + s u m 2 + c a l ( i , j ) , m a x ( s 1 , s 2 ) ) ) ans=min(ans,max(sum1+sum2+cal(i,j),max(s1,s2))) ans=min(ans,max(sum1+sum2+cal(i,j),max(s1,s2)))
其中 s 1 , s 2 s1,s2 s1,s2分别表示新边所连接的两个旧联通块的最长路。
但是这样就必须用并查集了。
时间复杂度: O ( n 3 α ( n ) ) O(n^3\alpha(n)) O(n3α(n))


代码:

/*
ID:ssl_zyc2
TASK:cowtour
LANG:C++
*/
#include <cstdio>
#include <cmath>
#include <iostream>
#include <cstring>
using namespace std;const int N=200;
const double Inf=1e9;
int n,x[N],y[N],map[N][N],father[N];
double dis[N][N],sum1,sum2,ans,maxn[N];double cal(double x1,double x2,double y1,double y2)
{return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}int find(int x)
{return x==father[x]?x:father[x]=find(father[x]);
}int main()
{freopen("cowtour.in","r",stdin);freopen("cowtour.out","w",stdout);ans=Inf;scanf("%d",&n);for (int i=1;i<=n;i++){scanf("%d%d",&x[i],&y[i]);father[i]=i;}for (int i=1;i<=n;i++)for (int j=1;j<=n;j++){scanf("%1d",&map[i][j]);if (map[i][j]==1){dis[i][j]=cal(x[i],x[j],y[i],y[j]);  //求路径长度father[find(j)]=find(i);}else dis[i][j]=Inf+1.0;}for (int k=1;k<=n;k++)  //Floydfor (int i=1;i<=n;i++)for (int j=1;j<=n;j++)if (i!=j&&j!=k&&k!=i)dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);for (int i=1;i<=n;i++)for (int j=1;j<=n;j++)if (find(i)==find(j)&&i!=j)maxn[find(i)]=max(maxn[find(i)],dis[i][j]);  //maxn[i]表示含i的联通块的最长路for (int i=1;i<=n;i++)for (int j=1;j<=n;j++)  //枚举任意两点if (i!=j&&find(i)!=find(j)){sum1=0;sum2=0;for (int k=1;k<=n;k++){if (find(i)==find(k)&&i!=k)sum1=max(sum1,dis[i][k]);if (find(j)==find(k)&&j!=k)sum2=max(sum2,dis[j][k]);}ans=min(ans,max(sum1+sum2+cal(x[i],x[j],y[i],y[j]),max(maxn[find(i)],maxn[find(j)])));}printf("%6lf\n",ans);return 0;
}

http://www.ppmy.cn/news/280915.html

相关文章

洛谷 P1522 牛的旅行 Cow Tours

题目&#xff1a;牛的旅行 思路&#xff1a; 先预处理出两点间的距离&#xff0c;跑一边floyd&#xff0c;然后处理出每个点到离它最远的和它连通的距离L[i]。 然后再对于每个点&#xff0c;枚举所有和它不连通的点j&#xff0c;用L[i]L[j]d(i,j)更新最小答案。 注意下&#x…

Flutter路由——Navigator2.0

Navigator 2.0提供了一系列全新的接口&#xff0c;可以实现将路由状态成为应用状态的一部分&#xff0c;新增的API如下&#xff1a; Page:用来表示Navigator路由栈中各个页面的不可变对象&#xff0c;Page是一个抽象类通常使用它的派生类&#xff1a;MaterialPage或CupertinoP…

P1522 [USACO2.4]牛的旅行 Cow Tours(Floyd多源最短路)

洛谷&#xff1a;牛的旅行 Cow son Tours 毒瘤题意&#xff08;确信&#xff09; 此题数据很小&#xff0c;但题意不好分析 洛谷题解整理的概念就很好&#xff08;分析能力%%%&#xff09;&#xff1a; 牧区&#xff1a; 对应一个点。牧区之间的距离&#xff1a;实际上是两点…

1522 N 叉树的直径

题目描述&#xff1a; 给定一棵 N 叉树的根节点 root &#xff0c;计算这棵树的直径长度。 N 叉树的直径指的是树中任意两个节点间路径中 最长 路径的长度。这条路径可能经过根节点&#xff0c;也可能不经过根节点。 &#xff08;N 叉树的输入序列以层序遍历的形式给出&#xf…

Oracle12c创建1522端口实例 和删除实例

1.手动添加1522监听 选第一项 添加 输入新监听名称 任意即可 输入你的oracl密码 ,也就是下载时候的密码 ,一般都是orcl 点击下一步完成创建即可 手动添加完监听&#xff0c;开始创建实例 以管理员身份运行cmd&#xff0c;输入dbca 第一个 全局数据库名就是你的实例名&…

洛谷 P1522

题目 链接&#xff1a;https://www.luogu.com.cn/problem/P1522 思路 这个题有些坑 1 可能重连接后没有之前长 最长的还是以前的 2 一个点也可能是一个区域 代码 #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include…

10g RAC 修改监听端口

11gRAC修改端口&#xff1a; http://blog.csdn.net/bamuta/article/details/29863943 11gRAC增加监听1&#xff1a; http://blog.csdn.net/bamuta/article/details/29865023 11gRAC增加监听2&#xff1a; http://blog.csdn.net/bamuta/article/details/300294…

给Oracle数据库换一个1522端口的监听

可能是因为短了几天&#xff0c;2月过得比其他月份要快不少。这都最后一天了&#xff0c;博客还是没碰一下。 也因为这个月学习放缓了&#xff0c;就是偷懒了。。所以想了想&#xff0c;定不下要写些什么。 很久以前就想写写分析函数&#xff0c;Oracle的分析函数是个强大的东…